Skip to content

Commit 095ddfe

Browse files
Merge pull request #26277 from lstocchi/i25038
HyperV machine should reuse hvsock registry entries when possible
2 parents 91816d9 + 901bd69 commit 095ddfe

File tree

9 files changed

+598
-117
lines changed

9 files changed

+598
-117
lines changed

pkg/machine/e2e/init_windows_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/Microsoft/go-winio/vhd"
1010
"github.com/containers/libhvee/pkg/hypervctl"
1111
"github.com/containers/podman/v6/pkg/machine/define"
12+
"github.com/containers/podman/v6/pkg/machine/hyperv/vsock"
1213
. "github.com/onsi/ginkgo/v2"
1314
. "github.com/onsi/gomega"
1415
. "github.com/onsi/gomega/gexec"
@@ -125,4 +126,106 @@ var _ = Describe("podman machine init - windows only", func() {
125126
Expect(err).ToNot(HaveOccurred())
126127
Expect(checkSession).To(Exit(125))
127128
})
129+
130+
It("init should create hvsock entries if they do not exist, otherwise should reuse existing ones", func() {
131+
skipIfNotVmtype(define.HyperVVirt, "HyperV test only")
132+
133+
name := randomString()
134+
135+
// Ensure no HVSock entries exist before we start
136+
networkHvSocks, err := vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Network)
137+
Expect(err).ToNot(HaveOccurred())
138+
Expect(networkHvSocks).To(BeEmpty())
139+
140+
readySocks, err := vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Events)
141+
Expect(err).ToNot(HaveOccurred())
142+
Expect(readySocks).To(BeEmpty())
143+
144+
fileServerVsocks, err := vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Fileserver)
145+
Expect(err).ToNot(HaveOccurred())
146+
Expect(fileServerVsocks).To(BeEmpty())
147+
148+
// Execute init for the first machine. This should create new HVSock entries
149+
i := new(initMachine)
150+
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath)).run()
151+
Expect(err).ToNot(HaveOccurred())
152+
Expect(session).To(Exit(0))
153+
154+
// Check that the HVSock entries were created
155+
networkHvSocks, err = vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Network)
156+
Expect(err).ToNot(HaveOccurred())
157+
Expect(networkHvSocks).To(HaveLen(1))
158+
159+
readySocks, err = vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Events)
160+
Expect(err).ToNot(HaveOccurred())
161+
Expect(readySocks).To(HaveLen(1))
162+
163+
fileServerVsocks, err = vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Fileserver)
164+
countFileServerVsocks := len(fileServerVsocks)
165+
Expect(err).ToNot(HaveOccurred())
166+
// check that many file server vsock was created
167+
Expect(countFileServerVsocks).To(BeNumerically(">", 1))
168+
169+
// Execute init for another machine. This should reuse the existing HVSock entries created above
170+
otherName := randomString()
171+
i = new(initMachine)
172+
session, err = mb.setName(otherName).setCmd(i.withImage(mb.imagePath)).run()
173+
Expect(err).ToNot(HaveOccurred())
174+
Expect(session).To(Exit(0))
175+
176+
newNetworkHvSocks, err := vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Network)
177+
Expect(err).ToNot(HaveOccurred())
178+
Expect(newNetworkHvSocks).To(HaveLen(1))
179+
Expect(newNetworkHvSocks[0].Port).To(Equal(networkHvSocks[0].Port))
180+
181+
newReadySocks, err := vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Events)
182+
Expect(err).ToNot(HaveOccurred())
183+
Expect(newReadySocks).To(HaveLen(1))
184+
Expect(newReadySocks[0].Port).To(Equal(readySocks[0].Port))
185+
186+
newFileServerVsocks, err := vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Fileserver)
187+
Expect(err).ToNot(HaveOccurred())
188+
Expect(newFileServerVsocks).To(HaveLen(countFileServerVsocks))
189+
for i := 0; i < countFileServerVsocks; i++ {
190+
Expect(newFileServerVsocks[i].Port).To(Equal(fileServerVsocks[i].Port))
191+
}
192+
193+
// remove first created machine
194+
rm := rmMachine{}
195+
removeSession, err := mb.setName(name).setCmd(rm.withForce()).run()
196+
Expect(err).ToNot(HaveOccurred())
197+
Expect(removeSession).To(Exit(0))
198+
199+
// Check that HVSock entries still exist after removing one machine
200+
networkHvSocks, err = vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Network)
201+
Expect(err).ToNot(HaveOccurred())
202+
Expect(networkHvSocks).To(HaveLen(1))
203+
204+
readySocks, err = vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Events)
205+
Expect(err).ToNot(HaveOccurred())
206+
Expect(readySocks).To(HaveLen(1))
207+
208+
fileServerVsocks, err = vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Fileserver)
209+
Expect(err).ToNot(HaveOccurred())
210+
Expect(fileServerVsocks).To(HaveLen(countFileServerVsocks))
211+
212+
// remove second created machine
213+
rm = rmMachine{}
214+
removeSession, err = mb.setName(otherName).setCmd(rm.withForce()).run()
215+
Expect(err).ToNot(HaveOccurred())
216+
Expect(removeSession).To(Exit(0))
217+
218+
// Verify all hvsock entries created during the test were removed
219+
networkHvSocks, err = vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Network)
220+
Expect(err).ToNot(HaveOccurred())
221+
Expect(networkHvSocks).To(BeEmpty())
222+
223+
readySocks, err = vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Events)
224+
Expect(err).ToNot(HaveOccurred())
225+
Expect(readySocks).To(BeEmpty())
226+
227+
fileServerVsocks, err = vsock.LoadAllHVSockRegistryEntriesByPurpose(vsock.Fileserver)
228+
Expect(err).ToNot(HaveOccurred())
229+
Expect(fileServerVsocks).To(BeEmpty())
230+
})
128231
})

pkg/machine/hyperv/hutil.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//go:build windows
2+
3+
package hyperv
4+
5+
import (
6+
"errors"
7+
8+
"github.com/sirupsen/logrus"
9+
"golang.org/x/sys/windows"
10+
)
11+
12+
var (
13+
ErrHypervUserNotInAdminGroup = errors.New("Hyper-V machines require Hyper-V admin rights to be managed. Please add the current user to the Hyper-V Administrators group or run Podman as an administrator")
14+
ErrHypervRegistryInitRequiresElevation = errors.New("the first time Podman initializes a Hyper-V machine, it requires admin rights. Please run Podman as an administrator")
15+
ErrHypervRegistryRemoveRequiresElevation = errors.New("removing this Hyper-V machine requires admin rights to clean up the Windows Registry. Please run Podman as an administrator")
16+
ErrHypervRegistryUpdateRequiresElevation = errors.New("this machine's configuration requires additional Hyper-V networking (hvsock) entries in the Windows Registry. Please run Podman as an administrator")
17+
)
18+
19+
func HasHyperVAdminRights() bool {
20+
sid, err := windows.CreateWellKnownSid(windows.WinBuiltinHyperVAdminsSid)
21+
if err != nil {
22+
return false
23+
}
24+
25+
// From MS docs:
26+
// "If TokenHandle is NULL, CheckTokenMembership uses the impersonation
27+
// token of the calling thread. If the thread is not impersonating,
28+
// the function duplicates the thread's primary token to create an
29+
// impersonation token."
30+
token := windows.Token(0)
31+
member, err := token.IsMember(sid)
32+
if err != nil {
33+
logrus.Warnf("Token Membership Error: %s", err)
34+
return false
35+
}
36+
37+
return member
38+
}

0 commit comments

Comments
 (0)