Skip to content

Commit c3dcf03

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 bac985d commit c3dcf03

File tree

21 files changed

+1999
-130
lines changed

21 files changed

+1999
-130
lines changed

cmd/gcs-sidecar/main.go

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

0 commit comments

Comments
 (0)