Skip to content

Commit 1ecfcfc

Browse files
committed
Add experimental krunkit provider support for macOS
Add CRC_PROVIDER env var to switch between vfkit and krunkit. Default provider: vfkit Set the env var to use krunkit Usage: ``` export CRC_PROVIDER=krunkit crc setup crc start ``` Note: Krunkit binary is signed with embedded hypervisor entitlements at cache time.
1 parent 11140c5 commit 1ecfcfc

File tree

10 files changed

+116
-33
lines changed

10 files changed

+116
-33
lines changed

pkg/crc/cache/cache.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func getVersionGeneric(executablePath string, args ...string) (string, error) {
5959
logging.Debugf("failed to run executable %s: %v", executablePath, err)
6060
return "", err
6161
}
62-
parsedOutput := strings.Split(stdOut, ":")
62+
parsedOutput := strings.Split(stdOut, " ")
6363
if len(parsedOutput) < 2 {
6464
logging.Debugf("failed to parse version information for %s: %s", executablePath, stdOut)
6565
return "", fmt.Errorf("Unable to parse the version information of %s", executablePath)
@@ -144,7 +144,45 @@ func (c *Cache) cacheExecutable() error {
144144
if err != nil {
145145
return err
146146
}
147+
if c.GetExecutableName() == constants.KrunkitCommand {
148+
err = signKrunkit(finalExecutablePath)
149+
if err != nil {
150+
return err
151+
}
152+
}
153+
}
154+
return nil
155+
}
156+
157+
func signKrunkit(executablePath string) error {
158+
const krunkitEntitlements = `<?xml version="1.0" encoding="UTF-8"?>
159+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
160+
<plist version="1.0">
161+
<dict>
162+
<key>com.apple.security.cs.disable-library-validation</key>
163+
<true/>
164+
<key>com.apple.security.hypervisor</key>
165+
<true/>
166+
</dict>
167+
</plist>
168+
`
169+
tmpFile, err := os.CreateTemp("", "krunkit-entitlements-*.plist")
170+
if err != nil {
171+
return fmt.Errorf("failed to create temp entitlements file: %w", err)
172+
}
173+
defer os.Remove(tmpFile.Name())
174+
175+
if _, err := tmpFile.WriteString(krunkitEntitlements); err != nil {
176+
tmpFile.Close()
177+
return fmt.Errorf("failed to write entitlements: %w", err)
178+
}
179+
tmpFile.Close()
180+
181+
_, _, err = crcos.RunWithDefaultLocale("codesign", "-s", "-", "--entitlements", tmpFile.Name(), "--force", executablePath)
182+
if err != nil {
183+
return err
147184
}
185+
logging.Debugf("Signed %s", executablePath)
148186
return nil
149187
}
150188

@@ -183,7 +221,7 @@ func (c *Cache) CheckVersion() error {
183221
}
184222

185223
func isTarball(filename string) bool {
186-
tarballExtensions := []string{".tar", ".tar.gz", ".tar.xz", ".zip", ".tar.bz2", ".crcbundle"}
224+
tarballExtensions := []string{".tar", ".tar.gz", ".tar.xz", ".zip", ".tar.bz2", ".crcbundle", ".tgz"}
187225
for _, extension := range tarballExtensions {
188226
if strings.HasSuffix(strings.ToLower(filename), extension) {
189227
return true

pkg/crc/cache/cache_darwin.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import (
77
)
88

99
func NewVfkitCache() *Cache {
10-
return newCache(vfkit.ExecutablePath(), vfkit.VfkitDownloadURL, vfkit.VfkitVersion, getVfkitVersion)
10+
return newCache(vfkit.ExecutablePath(), vfkit.DownloadURL(), vfkit.Version(), getVfkitVersion)
1111
}
1212

1313
func getVfkitVersion(executablePath string) (string, error) {
14-
version, err := getVersionGeneric(executablePath, "-v")
14+
version, err := getVersionGeneric(executablePath, "--version")
1515
if err != nil {
1616
return version, err
1717
}

pkg/crc/constants/constants_darwin.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
//go:build darwin
2+
13
package constants
24

35
import (
6+
"log"
7+
"os"
48
"path/filepath"
59
)
610

@@ -9,8 +13,27 @@ const (
913
PodmanRemoteExecutableName = "podman"
1014
DaemonAgentLabel = "com.redhat.crc.daemon"
1115
QemuGuestAgentPort = 1234
16+
17+
VfkitCommand = "vfkit"
18+
KrunkitCommand = "krunkit"
1219
)
1320

21+
func Provider() string {
22+
provider := os.Getenv("CRC_PROVIDER")
23+
if provider == "" {
24+
provider = VfkitCommand
25+
}
26+
switch provider {
27+
case VfkitCommand:
28+
return VfkitCommand
29+
case KrunkitCommand:
30+
return KrunkitCommand
31+
default:
32+
log.Fatalf("Invalid provider: %s. Choose between %s or %s", provider, VfkitCommand, KrunkitCommand)
33+
return ""
34+
}
35+
}
36+
1437
var (
1538
TapSocketPath = filepath.Join(CrcBaseDir, "tap.sock")
1639
DaemonHTTPSocketPath = filepath.Join(CrcBaseDir, "crc-http.sock")

pkg/crc/constants/constants_linux.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ const (
88
OcExecutableName = "oc"
99
PodmanRemoteExecutableName = "podman-remote"
1010
TapSocketPath = ""
11+
KrunkitCommand = ""
1112
)
1213

1314
var DaemonHTTPSocketPath = filepath.Join(CrcBaseDir, "crc-http.sock")
15+
16+
func Provider() string {
17+
return ""
18+
}

pkg/crc/constants/constants_windows.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,9 @@ const (
77
DaemonHTTPNamedPipe = `\\.\pipe\crc-http`
88
DaemonTaskName = "crcDaemon"
99
AdminHelperServiceName = "crcAdminHelper"
10+
KrunkitCommand = ""
1011
)
12+
13+
func Provider() string {
14+
return ""
15+
}

pkg/crc/machine/vfkit/constants.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,40 @@ import (
99
)
1010

1111
const (
12-
VfkitVersion = "0.6.1"
13-
vfkitCommand = "vfkit"
12+
VfkitVersion = "0.6.1"
13+
VfkitCommand = "vfkit"
14+
KrunkitVersion = "1.1.1"
15+
KrunkitCommand = "krunkit"
1416
)
1517

1618
var (
17-
VfkitDownloadURL = fmt.Sprintf("https://github.com/crc-org/vfkit/releases/download/v%s/%s", VfkitVersion, vfkitCommand)
19+
VfkitDownloadURL = fmt.Sprintf("https://github.com/crc-org/vfkit/releases/download/v%s/%s", VfkitVersion, VfkitCommand)
1820
VfkitEntitlementsURL = fmt.Sprintf("https://raw.githubusercontent.com/crc-org/vfkit/v%s/vf.entitlements", VfkitVersion)
21+
KrunkitDownloadURL = fmt.Sprintf("https://github.com/containers/krunkit/releases/download/v%s/krunkit-podman-unsigned-%s.tgz", KrunkitVersion, KrunkitVersion)
1922
)
2023

2124
func ExecutablePath() string {
22-
return constants.ResolveHelperPath(vfkitCommand)
25+
return constants.ResolveHelperPath(constants.Provider())
26+
}
27+
28+
func DownloadURL() string {
29+
switch constants.Provider() {
30+
case VfkitCommand:
31+
return VfkitDownloadURL
32+
case KrunkitCommand:
33+
return KrunkitDownloadURL
34+
default:
35+
return ""
36+
}
37+
}
38+
39+
func Version() string {
40+
switch constants.Provider() {
41+
case VfkitCommand:
42+
return VfkitVersion
43+
case KrunkitCommand:
44+
return KrunkitVersion
45+
default:
46+
return ""
47+
}
2348
}

pkg/crc/machine/vfkit/driver_darwin.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@ import (
1111
)
1212

1313
func CreateHost(machineConfig config.MachineConfig) *vfkit.Driver {
14-
vfDriver := vfkit.NewDriver(machineConfig.Name, constants.MachineBaseDir)
14+
vfDriver := vfkit.NewDriver(machineConfig.Name, constants.MachineBaseDir, VfkitCommand)
1515

1616
config.InitVMDriverFromMachineConfig(machineConfig, vfDriver.VMDriver)
1717

18-
vfDriver.VfkitPath = ExecutablePath()
19-
2018
vfDriver.VirtioNet = machineConfig.NetworkMode == network.SystemNetworkingMode
2119

2220
vfDriver.VsockPath = constants.TapSocketPath

pkg/crc/preflight/preflight_darwin.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ var vfkitPreflightChecks = []Check{
3333
},
3434
{
3535
configKeySuffix: "check-vfkit-installed",
36-
checkDescription: "Checking if vfkit is installed",
36+
checkDescription: "Checking if " + constants.Provider() + " is installed",
3737
check: checkVfkitInstalled,
38-
fixDescription: "Setting up virtualization with vfkit",
38+
fixDescription: "Setting up virtualization with " + constants.Provider(),
3939
fix: fixVfkitInstallation,
4040

4141
labels: labels{Os: Darwin},
4242
},
4343
{
44-
cleanupDescription: "Stopping CRC vfkit process",
44+
cleanupDescription: "Stopping CRC " + constants.Provider() + " process",
4545
cleanup: killVfkitProcess,
4646
flags: CleanUpOnly,
4747

pkg/drivers/vfkit/driver_darwin.go

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ type Driver struct {
5252
UnixgramSockPath string
5353
}
5454

55-
func NewDriver(hostName, storePath string) *Driver {
55+
func NewDriver(hostName, storePath, executableName string) *Driver {
5656
// checks that vfdriver.Driver implements the libmachine.Driver interface
5757
var _ drivers.Driver = &Driver{}
5858
return &Driver{
@@ -69,6 +69,7 @@ func NewDriver(hostName, storePath string) *Driver {
6969
DaemonVsockPort: constants.DaemonVsockPort,
7070
UnixgramSockPath: constants.UnixgramSocketPath,
7171
UnixgramMacAddress: constants.VsockMacAddress,
72+
VfkitPath: constants.ResolveHelperPath(executableName),
7273
}
7374
}
7475

@@ -272,20 +273,6 @@ func (d *Driver) Start() error {
272273
}
273274
}
274275

275-
// when loading a VM created by a crc version predating this commit,
276-
// d.QemuGAVsockPort will be missing from ~/.crc/machines/crc/config.json
277-
// In such a case, assume the VM will not support time sync
278-
if d.QemuGAVsockPort != 0 {
279-
timesync, err := config.TimeSyncNew(d.QemuGAVsockPort)
280-
if err != nil {
281-
return err
282-
}
283-
err = vm.AddDevice(timesync)
284-
if err != nil {
285-
return err
286-
}
287-
}
288-
289276
args, err := vm.ToCmdLine()
290277
if err != nil {
291278
return err
@@ -447,7 +434,7 @@ func (d *Driver) findVfkitProcess() (*process.Process, error) {
447434
if err != nil {
448435
return nil, err
449436
}
450-
if !strings.HasPrefix(name, "vfkit") {
437+
if !strings.HasPrefix(name, constants.Provider()) {
451438
// return InvalidExecutable error?
452439
log.Debugf("pid %d is stale, and is being used by %s", pid, name)
453440
return nil, nil

pkg/libmachine/load_darwin.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ package libmachine
33
import (
44
"encoding/json"
55

6-
"github.com/crc-org/crc/v2/pkg/drivers/vfkit"
6+
"github.com/crc-org/crc/v2/pkg/crc/constants"
7+
vfkitDriver "github.com/crc-org/crc/v2/pkg/drivers/vfkit"
78
"github.com/crc-org/crc/v2/pkg/libmachine/host"
89
)
910

1011
func (api *Client) NewHost(_ string, driverPath string, rawDriver []byte) (*host.Host, error) {
11-
driver := vfkit.NewDriver("", "")
12+
driver := vfkitDriver.NewDriver("", "", constants.Provider())
1213
if err := json.Unmarshal(rawDriver, &driver); err != nil {
1314
return nil, err
1415
}
@@ -29,10 +30,11 @@ func (api *Client) Load(name string) (*host.Host, error) {
2930
return nil, err
3031
}
3132

32-
driver := vfkit.NewDriver("", "")
33+
driver := vfkitDriver.NewDriver("", "", constants.Provider())
3334
if err := json.Unmarshal(h.RawDriver, &driver); err != nil {
3435
return nil, err
3536
}
37+
driver.VfkitPath = constants.ResolveHelperPath(constants.VfkitCommand)
3638
h.Driver = driver
3739
return h, nil
3840
}

0 commit comments

Comments
 (0)