Work around Sequoia's "Local Network" permission with a helper process (#302)
* Work around Sequoia's "Local Network" permission with a helper process * README.md: macOS 15 (Sequoia) warning * Make "orchard dev" unix-specific too, otherwise Release fails * Fix typo in "localNetworkHerlper" * Slightly improve the macOS 15 (Sequoia) note * orchard worker run: better documentation for --user * Make sure privilege dropping is the first step we do in runWorker()
This commit is contained in:
parent
fa38fe72ed
commit
abcfee677d
14
README.md
14
README.md
|
|
@ -1,5 +1,19 @@
|
|||
# Orchard
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> **macOS 15 (Sequoia)**
|
||||
>
|
||||
> The [newly introduced "Local Network" permission](https://developer.apple.com/documentation/technotes/tn3179-understanding-local-network-privacy) in macOS Sequoia requires accepting a GUI pop-up on each host machine that runs the Orchard Worker.
|
||||
>
|
||||
> To work around this, upgrade your workers to Orchard 0.32.0 or newer and invoke the `orchard worker run` as `root` with an additional `--user` command-line argument, which takes a name of your regular, non-privileged user on the host machine.
|
||||
>
|
||||
> This will cause the Orchard Worker to start a small `orchard localnetworkhelper` process in the background and then drop the privileges to the specified user.
|
||||
>
|
||||
>The helper process is privileged and needed to establish network connections on behalf of the Orchard Worker without triggering a GUI pop-up.
|
||||
>
|
||||
>This approach is more secure than simply running `orchard worker run` as `root`, because only a small part of Orchard Worker runs privileged and the only functionality that this part has is establishing new connections.
|
||||
|
||||
<img src="https://github.com/cirruslabs/orchard/raw/main/docs/OrchardSocial.png"/>
|
||||
|
||||
Orchard is an orchestration system for [Tart](https://github.com/cirruslabs/tart). Create a cluster of bare-metal Apple Silicon machines and manage dozens of VMs with ease!
|
||||
|
|
|
|||
13
go.mod
13
go.mod
|
|
@ -1,11 +1,13 @@
|
|||
module github.com/cirruslabs/orchard
|
||||
|
||||
go 1.23.3
|
||||
toolchain go1.24.1
|
||||
go 1.24
|
||||
|
||||
toolchain go1.24.2
|
||||
|
||||
require (
|
||||
github.com/avast/retry-go v3.0.0+incompatible
|
||||
github.com/avast/retry-go/v4 v4.6.1
|
||||
github.com/cirruslabs/chacha v0.10.0
|
||||
github.com/coder/websocket v1.8.13
|
||||
github.com/deckarep/golang-set/v2 v2.8.0
|
||||
github.com/dgraph-io/badger/v3 v3.2103.5
|
||||
|
|
@ -37,7 +39,7 @@ require (
|
|||
go.opentelemetry.io/otel/sdk/metric v1.35.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa
|
||||
golang.org/x/net v0.38.0
|
||||
golang.org/x/term v0.30.0
|
||||
google.golang.org/grpc v1.71.1
|
||||
|
|
@ -62,7 +64,7 @@ require (
|
|||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/containerd/console v1.0.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
|
|
@ -107,10 +109,11 @@ require (
|
|||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/puzpuzpuz/xsync/v4 v4.0.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
|
|
|
|||
14
go.sum
14
go.sum
|
|
@ -50,6 +50,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5O
|
|||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cirruslabs/chacha v0.10.0 h1:Ny/U7sVFkB3DAZM0PAvbkEX4/IN0bUI97XlQGx4kzzA=
|
||||
github.com/cirruslabs/chacha v0.10.0/go.mod h1:qbGp1psGAO8KfN4ZkXSHiTWkyZh9az5DUmLyP1ihe3g=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
|
|
@ -66,8 +68,9 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
|||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ=
|
||||
github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||
github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg=
|
||||
|
|
@ -240,8 +243,9 @@ github.com/penglongli/gin-metrics v0.1.13 h1:a1wyrXcbUVxL5w4c2TSv+9kyQA9qM1o23h0
|
|||
github.com/penglongli/gin-metrics v0.1.13/go.mod h1:VEmSyx/9TwUG50IsPCgjMKOUuGO74V2lmkLZ6x1Dlko=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
|
|
@ -260,6 +264,8 @@ github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5b
|
|||
github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
|
||||
github.com/pterm/pterm v0.12.80 h1:mM55B+GnKUnLMUSqhdINe4s6tOuVQIetQ3my8JGyAIg=
|
||||
github.com/pterm/pterm v0.12.80/go.mod h1:c6DeF9bSnOSeFPZlfs4ZRAFcf5SCoTwvwQ5xaKGQlHo=
|
||||
github.com/puzpuzpuz/xsync/v4 v4.0.0 h1:F1za+MBXzDQtQq+OVgFsojSX4w66rsNDmQNebPFAncA=
|
||||
github.com/puzpuzpuz/xsync/v4 v4.0.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
|
|
@ -354,8 +360,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
|||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//go:build unix
|
||||
|
||||
package dev
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
//go:build !unix
|
||||
|
||||
package dev
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
func NewCommand() *cobra.Command {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
//go:build unix
|
||||
|
||||
package localnetworkhelper
|
||||
|
||||
import (
|
||||
"github.com/cirruslabs/chacha/pkg/localnetworkhelper"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: localnetworkhelper.CommandName,
|
||||
Short: "Run the macOS \"Local Network\" permission helper process",
|
||||
Hidden: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// In localnetworkhelper.New(), a macOS "Local Network"
|
||||
// permission helper process is spawned and receives
|
||||
// its socketpair(2) end via ExtraFiles field of Golang's
|
||||
// exec.Cmd[1].
|
||||
//
|
||||
// This socketpair(2) end becomes FD number 3 here,
|
||||
// according to the ExtraFiles documentation[1]:
|
||||
//
|
||||
// >If non-nil, entry i becomes file descriptor 3+i.
|
||||
//
|
||||
// [1]: https://pkg.go.dev/os/exec#Cmd
|
||||
return localnetworkhelper.Serve(3)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
//go:build !unix
|
||||
|
||||
package localnetworkhelper
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewCommand() *cobra.Command {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/cirruslabs/orchard/internal/command/dev"
|
||||
"github.com/cirruslabs/orchard/internal/command/get"
|
||||
"github.com/cirruslabs/orchard/internal/command/list"
|
||||
"github.com/cirruslabs/orchard/internal/command/localnetworkhelper"
|
||||
"github.com/cirruslabs/orchard/internal/command/logs"
|
||||
"github.com/cirruslabs/orchard/internal/command/pause"
|
||||
"github.com/cirruslabs/orchard/internal/command/portforward"
|
||||
|
|
@ -37,6 +38,10 @@ func NewRootCmd() *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
if localNetworkHelperCommand := localnetworkhelper.NewCommand(); localNetworkHelperCommand != nil {
|
||||
command.AddCommand(localNetworkHelperCommand)
|
||||
}
|
||||
|
||||
addGroupedCommands(command, "Working With Resources:",
|
||||
create.NewCommand(),
|
||||
deletepkg.NewCommand(),
|
||||
|
|
@ -51,12 +56,20 @@ func NewRootCmd() *cobra.Command {
|
|||
vnc.NewCommand(),
|
||||
)
|
||||
|
||||
addGroupedCommands(command, "Administrative Tasks:",
|
||||
administrativeCommands := []*cobra.Command{
|
||||
context.NewCommand(),
|
||||
controller.NewCommand(),
|
||||
worker.NewCommand(),
|
||||
dev.NewCommand(),
|
||||
)
|
||||
}
|
||||
|
||||
if devCommand := dev.NewCommand(); devCommand != nil {
|
||||
administrativeCommands = append(administrativeCommands, devCommand)
|
||||
}
|
||||
|
||||
if workerCommand := worker.NewCommand(); workerCommand != nil {
|
||||
administrativeCommands = append(administrativeCommands, workerCommand)
|
||||
}
|
||||
|
||||
addGroupedCommands(command, "Administrative Tasks:", administrativeCommands...)
|
||||
|
||||
return command
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
//go:build unix
|
||||
|
||||
package worker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cirruslabs/chacha/pkg/localnetworkhelper"
|
||||
"github.com/cirruslabs/chacha/pkg/privdrop"
|
||||
"github.com/cirruslabs/orchard/internal/bootstraptoken"
|
||||
"github.com/cirruslabs/orchard/internal/netconstants"
|
||||
"github.com/cirruslabs/orchard/internal/worker"
|
||||
|
|
@ -32,6 +36,7 @@ var labels map[string]string
|
|||
var noPKI bool
|
||||
var defaultCPU uint64
|
||||
var defaultMemory uint64
|
||||
var username string
|
||||
var debug bool
|
||||
|
||||
func newRunCommand() *cobra.Command {
|
||||
|
|
@ -62,17 +67,46 @@ func newRunCommand() *cobra.Command {
|
|||
"that do not explicitly specify a value")
|
||||
cmd.PersistentFlags().Uint64Var(&defaultMemory, "default-memory", 8*1024, "megabytes of memory "+
|
||||
"to use for VMs that do not explicitly specify a value")
|
||||
cmd.Flags().StringVar(&username, "user", "", "username to drop privileges to "+
|
||||
"(\"Local Network\" permission workaround: requires starting \"orchard worker run\" as \"root\", "+
|
||||
"the privileges will be then dropped to the specified user after starting the \"orchard localnetworkhelper\" "+
|
||||
"helper process)")
|
||||
cmd.PersistentFlags().BoolVar(&debug, "debug", false, "enable debug logging")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runWorker(cmd *cobra.Command, args []string) (err error) {
|
||||
var clientOpts []client.Option
|
||||
|
||||
workerOpts := []worker.Option{
|
||||
worker.WithName(name),
|
||||
worker.WithLabels(labels),
|
||||
worker.WithDefaultCPUAndMemory(defaultCPU, defaultMemory),
|
||||
}
|
||||
|
||||
// Run the macOS "Local Network" permission helper
|
||||
// when privilege dropping is requested
|
||||
if username != "" {
|
||||
localNetworkHelper, err := localnetworkhelper.New(cmd.Context())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientOpts = append(clientOpts, client.WithDialContext(localNetworkHelper.PrivilegedDialContext))
|
||||
workerOpts = append(workerOpts, worker.WithLocalNetworkHelper(localNetworkHelper))
|
||||
|
||||
if err := privdrop.Drop(username); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Parse controller URL
|
||||
controllerURL, err := netconstants.NormalizeAddress(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clientOpts = append(clientOpts, client.WithAddress(controllerURL.String()))
|
||||
|
||||
// Parse bootstrap token
|
||||
bootstrapTokenRaw, err := readBootstrapToken()
|
||||
|
|
@ -86,17 +120,15 @@ func runWorker(cmd *cobra.Command, args []string) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clientOpts = append(clientOpts, client.WithCredentials(bootstrapToken.ServiceAccountName(),
|
||||
bootstrapToken.ServiceAccountToken()))
|
||||
|
||||
// Convert resources
|
||||
resources, err := v1.NewResourcesFromStringToString(stringToStringResources)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrRunFailed, err)
|
||||
}
|
||||
|
||||
clientOpts := []client.Option{
|
||||
client.WithAddress(controllerURL.String()),
|
||||
client.WithCredentials(bootstrapToken.ServiceAccountName(), bootstrapToken.ServiceAccountToken()),
|
||||
}
|
||||
workerOpts = append(workerOpts, worker.WithResources(resources))
|
||||
|
||||
if trustedCertificate := bootstrapToken.Certificate(); trustedCertificate != nil {
|
||||
clientOpts = append(clientOpts, client.WithTrustedCertificate(trustedCertificate))
|
||||
|
|
@ -120,14 +152,11 @@ func runWorker(cmd *cobra.Command, args []string) (err error) {
|
|||
err = syncErr
|
||||
}
|
||||
}()
|
||||
workerOpts = append(workerOpts, worker.WithLogger(logger))
|
||||
|
||||
workerInstance, err := worker.New(
|
||||
controllerClient,
|
||||
worker.WithName(name),
|
||||
worker.WithResources(resources),
|
||||
worker.WithLabels(labels),
|
||||
worker.WithDefaultCPUAndMemory(defaultCPU, defaultMemory),
|
||||
worker.WithLogger(logger),
|
||||
workerOpts...,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//go:build unix
|
||||
|
||||
package worker
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
//go:build !unix
|
||||
|
||||
package worker
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
func NewCommand() *cobra.Command {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"github.com/cirruslabs/chacha/pkg/localnetworkhelper"
|
||||
v1 "github.com/cirruslabs/orchard/pkg/resource/v1"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
|
@ -32,6 +33,12 @@ func WithDefaultCPUAndMemory(defaultCPU uint64, defaultMemory uint64) Option {
|
|||
}
|
||||
}
|
||||
|
||||
func WithLocalNetworkHelper(localNetworkHelper *localnetworkhelper.LocalNetworkHelper) Option {
|
||||
return func(worker *Worker) {
|
||||
worker.localNetworkHelper = localNetworkHelper
|
||||
}
|
||||
}
|
||||
|
||||
func WithLogger(logger *zap.Logger) Option {
|
||||
return func(worker *Worker) {
|
||||
worker.logger = logger.Sugar()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"github.com/avast/retry-go"
|
||||
"github.com/cirruslabs/chacha/pkg/localnetworkhelper"
|
||||
"github.com/cirruslabs/orchard/internal/worker/ondiskname"
|
||||
"github.com/cirruslabs/orchard/internal/worker/tart"
|
||||
"github.com/cirruslabs/orchard/pkg/client"
|
||||
|
|
@ -51,12 +52,15 @@ type VM struct {
|
|||
cancel context.CancelFunc
|
||||
|
||||
wg *sync.WaitGroup
|
||||
|
||||
localNetworkHelper *localnetworkhelper.LocalNetworkHelper
|
||||
}
|
||||
|
||||
func NewVM(
|
||||
vmResource v1.VM,
|
||||
eventStreamer *client.EventStreamer,
|
||||
vmPullTimeHistogram metric.Float64Histogram,
|
||||
localNetworkHelper *localnetworkhelper.LocalNetworkHelper,
|
||||
logger *zap.SugaredLogger,
|
||||
) *VM {
|
||||
vmContext, vmContextCancel := context.WithCancel(context.Background())
|
||||
|
|
@ -74,6 +78,8 @@ func NewVM(
|
|||
cancel: vmContextCancel,
|
||||
|
||||
wg: &sync.WaitGroup{},
|
||||
|
||||
localNetworkHelper: localNetworkHelper,
|
||||
}
|
||||
|
||||
vm.wg.Add(1)
|
||||
|
|
@ -429,11 +435,18 @@ func (vm *VM) shell(
|
|||
|
||||
addr := ip + ":22"
|
||||
|
||||
dialer := net.Dialer{
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
dialCtx, dialCtxCancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer dialCtxCancel()
|
||||
|
||||
netConn, err := dialer.DialContext(ctx, "tcp", addr)
|
||||
var netConn net.Conn
|
||||
|
||||
if vm.localNetworkHelper != nil {
|
||||
netConn, err = vm.localNetworkHelper.PrivilegedDialContext(dialCtx, "tcp", addr)
|
||||
} else {
|
||||
dialer := net.Dialer{}
|
||||
|
||||
netConn, err = dialer.DialContext(dialCtx, "tcp", addr)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to dial %s: %w", addr, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"github.com/avast/retry-go/v4"
|
||||
"github.com/cirruslabs/chacha/pkg/localnetworkhelper"
|
||||
"github.com/cirruslabs/orchard/internal/opentelemetry"
|
||||
"github.com/cirruslabs/orchard/internal/worker/dhcpleasetime"
|
||||
"github.com/cirruslabs/orchard/internal/worker/iokitregistry"
|
||||
|
|
@ -40,6 +41,8 @@ type Worker struct {
|
|||
|
||||
vmPullTimeHistogram metric.Float64Histogram
|
||||
|
||||
localNetworkHelper *localnetworkhelper.LocalNetworkHelper
|
||||
|
||||
logger *zap.SugaredLogger
|
||||
}
|
||||
|
||||
|
|
@ -409,7 +412,8 @@ func (worker *Worker) deleteVM(vm *vmmanager.VM) error {
|
|||
func (worker *Worker) createVM(odn ondiskname.OnDiskName, vmResource v1.VM) {
|
||||
eventStreamer := worker.client.VMs().StreamEvents(vmResource.Name)
|
||||
|
||||
vm := vmmanager.NewVM(vmResource, eventStreamer, worker.vmPullTimeHistogram, worker.logger)
|
||||
vm := vmmanager.NewVM(vmResource, eventStreamer, worker.vmPullTimeHistogram,
|
||||
worker.localNetworkHelper, worker.logger)
|
||||
|
||||
worker.vmm.Put(odn, vm)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ type Client struct {
|
|||
|
||||
serviceAccountName string
|
||||
serviceAccountToken string
|
||||
|
||||
dialContext func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
|
|
@ -77,15 +79,21 @@ func New(opts ...Option) (*Client, error) {
|
|||
}
|
||||
|
||||
// Instantiate the HTTP client
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: client.tlsConfig,
|
||||
}
|
||||
|
||||
if client.dialContext != nil {
|
||||
transport.DialContext = client.dialContext
|
||||
}
|
||||
|
||||
client.httpClient = &http.Client{
|
||||
// The default is zero, which means no timeout, which means that
|
||||
// the requests may hang indefinitely. See [1] for more details.
|
||||
//
|
||||
// [1]: https://github.com/cirruslabs/orchard/issues/152#issuecomment-1927091747
|
||||
Timeout: 30 * time.Second,
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: client.tlsConfig,
|
||||
},
|
||||
Timeout: 30 * time.Second,
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
url, err := url.Parse(client.address)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Option func(*Client)
|
||||
|
|
@ -24,3 +26,9 @@ func WithCredentials(serviceAccountName string, serviceAccountToken string) Opti
|
|||
client.serviceAccountToken = serviceAccountToken
|
||||
}
|
||||
}
|
||||
|
||||
func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) Option {
|
||||
return func(client *Client) {
|
||||
client.dialContext = dialContext
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue