Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
31 changes: 29 additions & 2 deletions cmd/crc/cmd/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os"
"os/signal"
"regexp"
"runtime"
"syscall"
"time"

Expand All @@ -24,6 +25,7 @@ import (
"github.com/crc-org/crc/v2/pkg/crc/constants"
"github.com/crc-org/crc/v2/pkg/crc/daemonclient"
"github.com/crc-org/crc/v2/pkg/crc/logging"
"github.com/crc-org/crc/v2/pkg/fileserver/fs9p"
"github.com/crc-org/machine/libmachine/drivers"
"github.com/docker/go-units"
"github.com/gorilla/handlers"
Expand Down Expand Up @@ -177,7 +179,7 @@ func run(configuration *types.Configuration) error {
}
}()

ln, err := vn.Listen("tcp", fmt.Sprintf("%s:80", configuration.GatewayIP))
ln, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, "80"))
if err != nil {
return err
}
Expand All @@ -193,7 +195,7 @@ func run(configuration *types.Configuration) error {
}
}()

networkListener, err := vn.Listen("tcp", fmt.Sprintf("%s:80", hostVirtualIP))
networkListener, err := vn.Listen("tcp", net.JoinHostPort(hostVirtualIP, "80"))
if err != nil {
return err
}
Expand Down Expand Up @@ -248,6 +250,31 @@ func run(configuration *types.Configuration) error {
}
}()

// 9p home directory sharing
if runtime.GOOS == "windows" && config.Get(crcConfig.EnableSharedDirs).AsBool() {
listener9p, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, fmt.Sprintf("%d", constants.Plan9TcpPort)))
if err != nil {
return err
}
server9p, err := fs9p.New9pServer(listener9p, constants.GetHomeDir())
if err != nil {
return err
}
if err := server9p.Start(); err != nil {
return err
}
defer func() {
if err := server9p.Stop(); err != nil {
logging.Warnf("error stopping 9p server: %v", err)
}
}()
go func() {
if err := server9p.WaitForError(); err != nil {
logging.Errorf("9p server error: %v", err)
}
}()
}

startupDone()

if logging.IsDebug() {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.24.0

require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/DeedleFake/p9 v0.7.1
github.com/Masterminds/semver/v3 v3.4.0
github.com/Microsoft/go-winio v0.6.2
github.com/ProtonMail/go-crypto v1.3.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkk
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/DeedleFake/p9 v0.7.1 h1:HS4iPmbxR32pmtUyjNxXIf7eFih07Rxp1E0R6fqA7ik=
github.com/DeedleFake/p9 v0.7.1/go.mod h1:xFOErTOZm4lVysPCTrRtTm1c8J0Pfg0jGEC+re1AnIo=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
Expand Down
3 changes: 3 additions & 0 deletions pkg/crc/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ const (
OpenShiftIngressHTTPSPort = 443

BackgroundLauncherExecutable = "crc-background-launcher.exe"

Plan9Msize = 1024 * 1024
Plan9TcpPort = 564
)

var adminHelperExecutableForOs = map[string]string{
Expand Down
9 changes: 8 additions & 1 deletion pkg/crc/machine/libhvee/driver_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,14 @@ func configureShareDirs(machineConfig config.MachineConfig) []drivers.SharedDir
Type: "cifs",
Username: machineConfig.SharedDirUsername,
}
sharedDirs = append(sharedDirs, sharedDir)
sharedDir9p := drivers.SharedDir{
Source: dir,
Target: convertToUnixPath(dir) + "9p", // temporary solution until smb sharing is removed
Tag: "crc-dir0", // same as above
//Tag: fmt.Sprintf("dir%d", i),
Type: "9p",
}
sharedDirs = append(sharedDirs, sharedDir, sharedDir9p)
}
return sharedDirs
}
11 changes: 11 additions & 0 deletions pkg/crc/machine/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ func configureSharedDirs(vm *virtualMachine, sshRunner *crcssh.Runner) error {
if _, _, err := sshRunner.RunPrivileged(fmt.Sprintf("Mounting %s", mount.Target), "mount", "-o", "context=\"system_u:object_r:container_file_t:s0\"", "-t", mount.Type, mount.Tag, mount.Target); err != nil {
return err
}

case "cifs":
smbUncPath := fmt.Sprintf("//%s/%s", hostVirtualIP, mount.Tag)
if _, _, err := sshRunner.RunPrivate("sudo", "mount", "-o", fmt.Sprintf("rw,uid=core,gid=core,username='%s',password='%s'", mount.Username, mount.Password), "-t", mount.Type, smbUncPath, mount.Target); err != nil {
Expand All @@ -257,6 +258,16 @@ func configureSharedDirs(vm *virtualMachine, sshRunner *crcssh.Runner) error {
}
return fmt.Errorf("Failed to mount CIFS/SMB share '%s' please make sure configured password is correct: %w", mount.Tag, err)
}

case "9p":
// change owner to core user to allow mounting to it as a non-root user
if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown", "core:core", mount.Target); err != nil {
return err
}
if _, _, err := sshRunner.Run("9pfs", constants.VSockGateway, mount.Target); err != nil {
return err
}

default:
return fmt.Errorf("Unknown Shared dir type requested: %s", mount.Type)
}
Expand Down
98 changes: 98 additions & 0 deletions pkg/fileserver/fs9p/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package fs9p

import (
"errors"
"fmt"
"net"
"os"
"path/filepath"
"strings"

"github.com/DeedleFake/p9"
"github.com/DeedleFake/p9/proto"
"github.com/crc-org/crc/v2/pkg/crc/constants"
"github.com/sirupsen/logrus"
)

type Server struct {
// Listener this server is bound to
Listener net.Listener

// Plan9 Filesystem type that holds the exposed directory
Filesystem p9.FileSystem

// Directory this server exposes
ExposedDir string

// Errors from the server being started will come out here
ErrChan chan error
}

// New9pServer exposes a single directory (and all children) via the given net.Listener
// and returns the server struct.
// Directory given must be an absolute path and must exist.
func New9pServer(listener net.Listener, exposeDir string) (*Server, error) {
// verify that exposeDir makes sense
if !filepath.IsAbs(exposeDir) {
return nil, fmt.Errorf("path to expose to machine must be absolute: %s", exposeDir)
}
stat, err := os.Stat(exposeDir)
if err != nil {
return nil, fmt.Errorf("cannot stat path to expose to machine: %w", err)
}
if !stat.IsDir() {
return nil, fmt.Errorf("path to expose to machine must be a directory: %s", exposeDir)
}

fs := p9.FileSystem(p9.Dir(exposeDir))
// set size to 1 making channel buffered to prevent proto.Serve blocking
errChan := make(chan error, 1)

toReturn := new(Server)
toReturn.Listener = listener
toReturn.Filesystem = fs
toReturn.ExposedDir = exposeDir
toReturn.ErrChan = errChan

return toReturn, nil
}

// Start a server created by New9pServer.
func (s *Server) Start() error {
go func() {
s.ErrChan <- proto.Serve(s.Listener, p9.Proto(), p9.FSConnHandler(s.Filesystem, constants.Plan9Msize))
close(s.ErrChan)
}()

// Just before returning, check to see if we got an error off server startup.
select {
case err := <-s.ErrChan:
return fmt.Errorf("starting 9p server: %w", err)
default:
logrus.Infof("started 9p server on %s for directory %s", s.Listener.Addr().String(), s.ExposedDir)
return nil
}
}

// Stop a running server.
// Please note that this does *BAD THINGS* to clients if they are still running
// when the server stops. Processes get stuck in I/O deep sleep and zombify, and
// nothing I do other than restarting the VM can remove the zombies.
func (s *Server) Stop() error {
if err := s.Listener.Close(); err != nil {
return err
}
logrus.Infof("stopped 9p server for directory %s", s.ExposedDir)
return nil
}

// WaitForError from a running server.
func (s *Server) WaitForError() error {
err := <-s.ErrChan
// captures "accept tcp: endpoint is in invalid state" errors on exit
var opErr *net.OpError
if errors.As(err, &opErr) && strings.Contains(opErr.Error(), "endpoint is in invalid state") {
return nil
}
return err
}
21 changes: 21 additions & 0 deletions vendor/github.com/DeedleFake/p9/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions vendor/github.com/DeedleFake/p9/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 78 additions & 0 deletions vendor/github.com/DeedleFake/p9/addr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading