orchard worker run: introduce "--synthetic" and "--workers" hidden flags (#390)

* orchard worker run: introduce "--synthetic" and "--workers" hidden flags

* Use slices.Clone() instead of directly assigning slices

* Use errgroup's context instead of command's context
This commit is contained in:
Nikolay Edigaryev 2026-01-28 16:50:25 +01:00 committed by GitHub
parent 7775515a73
commit a234ec8995
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 106 additions and 31 deletions

View File

@ -11,6 +11,7 @@ import (
"os"
"path"
"path/filepath"
"slices"
"github.com/cirruslabs/orchard/internal/config"
"github.com/cirruslabs/orchard/internal/controller"
@ -142,21 +143,15 @@ func runDev(cmd *cobra.Command, args []string) error {
return devController.Run(ctx)
})
workerName, err := worker.DefaultName()
if err != nil {
return err
}
for i := range workers {
group.Go(func() error {
workerNameLocal := workerName
workerOptsLocal := slices.Clone(additionalWorkerOpts)
if workers > 1 {
workerNameLocal = fmt.Sprintf("%s-%d", workerName, i)
workerOptsLocal = append(workerOptsLocal, worker.WithNameSuffix(fmt.Sprintf("-%d", i+1)))
}
devWorker, err := CreateDevWorker(devClient, resources,
append(additionalWorkerOpts, worker.WithName(workerNameLocal)), logger)
devWorker, err := CreateDevWorker(devClient, resources, workerOptsLocal, logger)
if err != nil {
return err
}

View File

@ -11,12 +11,14 @@ import (
"net/http"
_ "net/http/pprof"
"os"
"slices"
"strings"
"github.com/cirruslabs/chacha/pkg/localnetworkhelper"
"github.com/cirruslabs/chacha/pkg/privdrop"
"github.com/cirruslabs/orchard/internal/bootstraptoken"
"github.com/cirruslabs/orchard/internal/dialer"
"github.com/cirruslabs/orchard/internal/echoserver"
"github.com/cirruslabs/orchard/internal/netconstants"
"github.com/cirruslabs/orchard/internal/worker"
"github.com/cirruslabs/orchard/pkg/client"
@ -24,6 +26,7 @@ import (
"github.com/spf13/cobra"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"golang.org/x/sync/errgroup"
"gopkg.in/natefinch/lumberjack.v2"
)
@ -46,6 +49,10 @@ var username string
var addressPprof string
var debug bool
// Hidden flags
var synthetic bool
var workers int
func newRunCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "run CONTROLLER_URL",
@ -82,6 +89,14 @@ func newRunCommand() *cobra.Command {
"start pprof HTTP server on localhost:6060 for diagnostic purposes (e.g. \"localhost:6060\")")
cmd.Flags().BoolVar(&debug, "debug", false, "enable debug logging")
// Hidden flags
cmd.Flags().BoolVar(&synthetic, "synthetic", false,
"do not instantiate real Tart VM, use synthetic in-memory VMs suitable for load testing")
cmd.Flags().MarkHidden("synthetic")
cmd.Flags().IntVar(&workers, "workers", 1, "number of workers to start")
cmd.Flags().MarkHidden("workers")
return cmd
}
@ -175,16 +190,49 @@ func runWorker(cmd *cobra.Command, args []string) (err error) {
}()
}
workerInstance, err := worker.New(
controllerClient,
workerOpts...,
)
if err != nil {
return err
}
defer workerInstance.Close()
group, ctx := errgroup.WithContext(cmd.Context())
return workerInstance.Run(cmd.Context())
if synthetic {
// Use TCP echo server to partially emulate VM's TCP/IP stack,
// this way we get port-forwarding working when running in
// synthetic mode
echoServer, err := echoserver.New()
if err != nil {
return err
}
group.Go(func() error {
return echoServer.Run(ctx)
})
dialer := dialer.DialFunc(func(ctx context.Context, network, addr string) (net.Conn, error) {
dialer := net.Dialer{}
return dialer.DialContext(ctx, "tcp", echoServer.Addr())
})
workerOpts = append(workerOpts, worker.WithSynthetic(), worker.WithDialer(dialer))
}
for i := range workers {
group.Go(func() error {
workerOptsLocal := slices.Clone(workerOpts)
if workers > 1 {
workerOptsLocal = append(workerOptsLocal, worker.WithNameSuffix(fmt.Sprintf("-%d", i+1)))
}
workerInstance, err := worker.New(controllerClient, workerOptsLocal...)
if err != nil {
return err
}
defer workerInstance.Close()
return workerInstance.Run(ctx)
})
}
return group.Wait()
}
func readBootstrapToken() (string, error) {

View File

@ -14,6 +14,12 @@ func WithName(name string) Option {
}
}
func WithNameSuffix(nameSuffix string) Option {
return func(worker *Worker) {
worker.nameSuffix = nameSuffix
}
}
func WithResources(resources v1.Resources) Option {
return func(worker *Worker) {
worker.resources = resources

View File

@ -3,8 +3,9 @@ package iokitregistry
import (
"errors"
"fmt"
"howett.net/plist"
"os/exec"
"howett.net/plist"
)
var ErrFailed = errors.New("failed to query I/O Kit registry")

View File

@ -1,10 +1,11 @@
package iokitregistry_test
import (
"github.com/cirruslabs/orchard/internal/worker/iokitregistry"
"testing"
"github.com/cirruslabs/orchard/internal/worker/platform/iokitregistry"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"testing"
)
func TestPlatformUUID(t *testing.T) {

View File

@ -0,0 +1,7 @@
package platform
import "github.com/cirruslabs/orchard/internal/worker/platform/iokitregistry"
func MachineID() (string, error) {
return iokitregistry.PlatformUUID()
}

View File

@ -0,0 +1,14 @@
package platform
import (
"os"
)
func MachineID() (string, error) {
machineIDBytes, err := os.ReadFile("/etc/machine-id")
if err != nil {
return "", err
}
return string(machineIDBytes), nil
}

View File

@ -12,8 +12,8 @@ import (
"github.com/cirruslabs/orchard/internal/dialer"
"github.com/cirruslabs/orchard/internal/opentelemetry"
"github.com/cirruslabs/orchard/internal/worker/dhcpleasetime"
"github.com/cirruslabs/orchard/internal/worker/iokitregistry"
"github.com/cirruslabs/orchard/internal/worker/ondiskname"
"github.com/cirruslabs/orchard/internal/worker/platform"
"github.com/cirruslabs/orchard/internal/worker/vmmanager"
"github.com/cirruslabs/orchard/internal/worker/vmmanager/synthetic"
"github.com/cirruslabs/orchard/internal/worker/vmmanager/tart"
@ -38,6 +38,7 @@ var ErrPollFailed = errors.New("failed to poll controller")
type Worker struct {
name string
nameSuffix string
syncRequested chan bool
vmm *vmmanager.VMManager
client *client.Client
@ -72,12 +73,16 @@ func New(client *client.Client, opts ...Option) (*Worker, error) {
// Apply defaults
if worker.name == "" {
name, err := DefaultName()
hostname, err := os.Hostname()
if err != nil {
return nil, err
}
worker.name = name
worker.name = hostname
}
if worker.nameSuffix != "" {
worker.name += worker.nameSuffix
}
defaultResources := v1.Resources{
@ -120,8 +125,10 @@ func New(client *client.Client, opts ...Option) (*Worker, error) {
}
func (worker *Worker) Run(ctx context.Context) error {
if err := dhcpleasetime.Check(); err != nil {
worker.logger.Warnf("%v", err)
if !worker.synthetic {
if err := dhcpleasetime.Check(); err != nil {
worker.logger.Warnf("%v", err)
}
}
for {
@ -228,12 +235,8 @@ func (worker *Worker) runNewSession(ctx context.Context) error {
}
}
func DefaultName() (string, error) {
return os.Hostname()
}
func (worker *Worker) registerWorker(ctx context.Context) error {
platformUUID, err := iokitregistry.PlatformUUID()
platformUUID, err := platform.MachineID()
if err != nil {
return err
}