Skip to content

Commit a1d186f

Browse files
committed
gcs-sidecar framework
This commit makes the high level changes needed for gcs-sidecar - Starts sidecar as service - Dereferences the various valid rpc requests - Adds code to invoke refs formatter Note: This commit does not add invokers to the code for new ResourceTypes like SecurityPolicy, CWCOWBlockCIMs, Container scratch formatting etc. This will come in along with functional tests in later PRs. There are some TODO comments in the code which will be addressed in upcoming PRs as well. To make this initialization of the gcs-sidecar flow complete, certain high level code for the policy enforcement have been brought into this commit from Mahati's changes. Example: internal/gcs-sidecar/policy.go, internal/gcs-sidecar/host.go and helper functions in internal/gcs-sidecar/host.go. Hence adding her as co-author in this commit. The rest of the policy framework code will be brought in by Mahati as follow up PRs. Co-authored-by: <[email protected]> Signed-off-by: Kirtana Ashok <[email protected]>
1 parent 0011e2e commit a1d186f

File tree

24 files changed

+1965
-138
lines changed

24 files changed

+1965
-138
lines changed

cmd/gcs-sidecar/main.go

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package main
5+
6+
import (
7+
"context"
8+
"flag"
9+
"fmt"
10+
"net"
11+
"os"
12+
13+
"github.com/Microsoft/go-winio"
14+
"github.com/Microsoft/hcsshim/internal/gcs/prot"
15+
shimlog "github.com/Microsoft/hcsshim/internal/log"
16+
"github.com/Microsoft/hcsshim/internal/oc"
17+
"github.com/Microsoft/hcsshim/pkg/securitypolicy"
18+
"github.com/sirupsen/logrus"
19+
"go.opencensus.io/trace"
20+
"golang.org/x/sys/windows"
21+
"golang.org/x/sys/windows/svc"
22+
"golang.org/x/sys/windows/svc/debug"
23+
24+
sidecar "github.com/Microsoft/hcsshim/internal/gcs-sidecar"
25+
)
26+
27+
var (
28+
defaultLogFile = "C:\\gcs-sidecar-logs.log"
29+
defaultLogLevel = "trace"
30+
)
31+
32+
type handler struct {
33+
fromsvc chan error
34+
}
35+
36+
// Accepts new connection and closes listener.
37+
func acceptAndClose(ctx context.Context, l net.Listener) (net.Conn, error) {
38+
var conn net.Conn
39+
ch := make(chan error)
40+
go func() {
41+
var err error
42+
conn, err = l.Accept()
43+
ch <- err
44+
}()
45+
select {
46+
case err := <-ch:
47+
l.Close()
48+
return conn, err
49+
case <-ctx.Done():
50+
}
51+
l.Close()
52+
err := <-ch
53+
if err == nil {
54+
return conn, err
55+
}
56+
57+
if ctx.Err() != nil {
58+
return nil, ctx.Err()
59+
}
60+
return nil, err
61+
}
62+
63+
func (h *handler) Execute(args []string, r <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) {
64+
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.Accepted(windows.SERVICE_ACCEPT_PARAMCHANGE)
65+
66+
status <- svc.Status{State: svc.StartPending, Accepts: 0}
67+
// unblock runService()
68+
h.fromsvc <- nil
69+
70+
status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
71+
72+
loop:
73+
for c := range r {
74+
switch c.Cmd {
75+
case svc.Interrogate:
76+
status <- c.CurrentStatus
77+
case svc.Stop, svc.Shutdown:
78+
logrus.Println("Shutting service...!")
79+
break loop
80+
case svc.Pause:
81+
status <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
82+
case svc.Continue:
83+
status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
84+
default:
85+
logrus.Printf("Unexpected service control request #%d", c)
86+
}
87+
}
88+
89+
status <- svc.Status{State: svc.StopPending}
90+
return false, 1
91+
}
92+
93+
func runService(name string, isDebug bool) error {
94+
h := &handler{
95+
fromsvc: make(chan error),
96+
}
97+
98+
var err error
99+
go func() {
100+
if isDebug {
101+
err := debug.Run(name, h)
102+
if err != nil {
103+
logrus.Fatalf("Error running service in debug mode.Err: %v", err)
104+
}
105+
} else {
106+
err := svc.Run(name, h)
107+
if err != nil {
108+
logrus.Fatalf("Error running service in Service Control mode.Err %v", err)
109+
}
110+
}
111+
h.fromsvc <- err
112+
}()
113+
114+
// Wait for the first signal from the service handler.
115+
logrus.Tracef("waiting for first signal from service handler\n")
116+
err = <-h.fromsvc
117+
if err != nil {
118+
return err
119+
}
120+
return nil
121+
122+
}
123+
124+
func main() {
125+
logLevel := flag.String("loglevel",
126+
defaultLogLevel,
127+
"Logging Level: trace, debug, info, warning, error, fatal, panic.")
128+
logFile := flag.String("logfile",
129+
defaultLogFile,
130+
"Logging Target. Default is at C:\\gcs-sidecar-logs.log inside UVM")
131+
132+
flag.Usage = func() {
133+
fmt.Fprintf(os.Stderr, "\nUsage of %s:\n", os.Args[0])
134+
flag.PrintDefaults()
135+
fmt.Fprintf(os.Stderr, "Examples:\n")
136+
fmt.Fprintf(os.Stderr, " %s -loglevel=trace -logfile=C:\\sidecarLogs.log \n", os.Args[0])
137+
}
138+
139+
flag.Parse()
140+
141+
ctx := context.Background()
142+
logFileHandle, err := os.OpenFile(*logFile, os.O_RDWR|os.O_CREATE|os.O_SYNC|os.O_TRUNC, 0666)
143+
if err != nil {
144+
fmt.Printf("error opening file: %v", err)
145+
}
146+
defer logFileHandle.Close()
147+
148+
logrus.AddHook(shimlog.NewHook())
149+
150+
level, err := logrus.ParseLevel(*logLevel)
151+
if err != nil {
152+
logrus.Fatal(err)
153+
}
154+
logrus.SetLevel(level)
155+
logrus.SetOutput(logFileHandle)
156+
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
157+
trace.RegisterExporter(&oc.LogrusExporter{})
158+
159+
if err := windows.SetStdHandle(windows.STD_ERROR_HANDLE, windows.Handle(logFileHandle.Fd())); err != nil {
160+
logrus.WithError(err).Error("error redirecting handle")
161+
return
162+
}
163+
os.Stderr = logFileHandle
164+
165+
chsrv := make(chan error)
166+
go func() {
167+
defer close(chsrv)
168+
169+
if err := runService("gcs-sidecar", false); err != nil {
170+
logrus.Fatalf("error starting gcs-sidecar service: %v", err)
171+
}
172+
173+
chsrv <- err
174+
}()
175+
176+
select {
177+
case <-ctx.Done():
178+
logrus.Fatalln("context deadline exceeded")
179+
return
180+
case r := <-chsrv:
181+
if r != nil {
182+
logrus.Fatal(r)
183+
return
184+
}
185+
}
186+
187+
// 1. Start external server to connect with inbox GCS
188+
listener, err := winio.ListenHvsock(&winio.HvsockAddr{
189+
VMID: prot.HvGUIDLoopback,
190+
ServiceID: prot.WindowsGcsHvsockServiceID,
191+
})
192+
if err != nil {
193+
logrus.WithError(err).Errorf("error starting listener for sidecar <-> inbox gcs communication")
194+
return
195+
}
196+
197+
var gcsListener net.Listener = listener
198+
gcsCon, err := acceptAndClose(ctx, gcsListener)
199+
if err != nil {
200+
logrus.WithError(err).Errorf("error accepting inbox GCS connection")
201+
return
202+
}
203+
204+
// 2. Setup connection with external gcs connection started from hcsshim
205+
hvsockAddr := &winio.HvsockAddr{
206+
VMID: prot.HvGUIDParent,
207+
ServiceID: prot.WindowsSidecarGcsHvsockServiceID,
208+
}
209+
210+
logrus.WithFields(logrus.Fields{
211+
"hvsockAddr": hvsockAddr,
212+
}).Tracef("Dialing to hcsshim external bridge at address %v", hvsockAddr)
213+
shimCon, err := winio.Dial(ctx, hvsockAddr)
214+
if err != nil {
215+
logrus.WithError(err).Errorf("error dialing hcsshim external bridge")
216+
return
217+
}
218+
219+
// gcs-sidecar can be used for non-confidentail hyperv wcow
220+
// as well. So we do not always want to check for initialPolicyStance
221+
var initialEnforcer securitypolicy.SecurityPolicyEnforcer
222+
// TODO (kiashok/Mahati): The initialPolicyStance is set to allow
223+
// only for dev. This will eventually be set to allow/deny depending on
224+
// on whether SNP is supported or not.
225+
initialPolicyStance := "allow"
226+
switch initialPolicyStance {
227+
case "allow":
228+
initialEnforcer = &securitypolicy.OpenDoorSecurityPolicyEnforcer{}
229+
logrus.Tracef("initial-policy-stance: allow")
230+
case "deny":
231+
initialEnforcer = &securitypolicy.ClosedDoorSecurityPolicyEnforcer{}
232+
logrus.Tracef("initial-policy-stance: deny")
233+
default:
234+
logrus.Error("unknown initial-policy-stance")
235+
}
236+
237+
// 3. Create bridge and initializa
238+
brdg := sidecar.NewBridge(shimCon, gcsCon, initialEnforcer)
239+
brdg.AssignHandlers()
240+
241+
// 3. Listen and serve for hcsshim requests.
242+
err = brdg.ListenAndServeShimRequests()
243+
if err != nil {
244+
logrus.WithError(err).Errorf("failed to serve request")
245+
}
246+
}

0 commit comments

Comments
 (0)