Skip to content

Commit fac5f0a

Browse files
committed
1
1 parent a6a4c50 commit fac5f0a

File tree

14 files changed

+270
-107
lines changed

14 files changed

+270
-107
lines changed

components/registry-facade/pkg/registry/manifest.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ func (mh *manifestHandler) getManifest(w http.ResponseWriter, r *http.Request) {
192192
return err
193193
}
194194
manifest.Layers = append(manifest.Layers, addonLayer...)
195+
cfg.Config.Labels = make(map[string]string)
196+
cfg.Config.Labels["test"] = "we can write workspace image ref and size here"
195197

196198
// place config in store
197199
rawCfg, err := json.Marshal(cfg)

components/ws-daemon/pkg/container/container.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"context"
99

1010
"golang.org/x/xerrors"
11+
12+
workspacev1 "github.com/gitpod-io/gitpod/ws-manager/api/crd/v1"
1113
)
1214

1315
// Runtime abstracts over the different container runtimes out there w.r.t. to the features we need from those runtimes
@@ -47,6 +49,8 @@ type Runtime interface {
4749

4850
// IsContainerdReady returns is the status of containerd.
4951
IsContainerdReady(ctx context.Context) (bool, error)
52+
53+
GetContainerImageInfo(ctx context.Context, id ID) (*workspacev1.WorkspaceImageInfo, error)
5054
}
5155

5256
var (

components/ws-daemon/pkg/container/containerd.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
wsk8s "github.com/gitpod-io/gitpod/common-go/kubernetes"
2929
"github.com/gitpod-io/gitpod/common-go/log"
3030
"github.com/gitpod-io/gitpod/common-go/tracing"
31+
workspacev1 "github.com/gitpod-io/gitpod/ws-manager/api/crd/v1"
3132
)
3233

3334
const (
@@ -92,6 +93,7 @@ type containerInfo struct {
9293
UpperDir string
9394
CGroupPath string
9495
PID uint32
96+
ImageRef string
9597
}
9698

9799
// start listening to containerd
@@ -276,6 +278,7 @@ func (s *Containerd) handleNewContainer(c containers.Container) {
276278
info.ID = c.ID
277279
info.SnapshotKey = c.SnapshotKey
278280
info.Snapshotter = c.Snapshotter
281+
info.ImageRef = c.Image
279282

280283
s.cntIdx[c.ID] = info
281284
log.WithField("podname", podName).WithFields(log.OWI(info.OwnerID, info.WorkspaceID, info.InstanceID)).WithField("ID", c.ID).Debug("found workspace container - updating label cache")
@@ -480,6 +483,35 @@ func (s *Containerd) ContainerPID(ctx context.Context, id ID) (pid uint64, err e
480483
return uint64(info.PID), nil
481484
}
482485

486+
func (s *Containerd) GetContainerImageInfo(ctx context.Context, id ID) (*workspacev1.WorkspaceImageInfo, error) {
487+
info, ok := s.cntIdx[string(id)]
488+
if !ok {
489+
return nil, ErrNotFound
490+
}
491+
492+
image, err := s.Client.GetImage(ctx, info.ImageRef)
493+
if err != nil {
494+
return nil, err
495+
}
496+
size, err := image.Size(ctx)
497+
if err != nil {
498+
return nil, err
499+
}
500+
501+
wsImageInfo := &workspacev1.WorkspaceImageInfo{
502+
TotalSize: size,
503+
}
504+
505+
sp, err := image.Spec(ctx)
506+
if err != nil {
507+
log.WithError(err).Error("cannot get image spec")
508+
} else {
509+
log.WithField("labels", log.TrustedValueWrap{Value: sp.Config.Labels}).Info("image spec ---------- ")
510+
}
511+
512+
return wsImageInfo, nil
513+
}
514+
483515
func (s *Containerd) IsContainerdReady(ctx context.Context) (bool, error) {
484516
if len(s.registryFacadeHost) == 0 {
485517
return s.Client.IsServing(ctx)

components/ws-daemon/pkg/controller/mock.go

Lines changed: 6 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ws-daemon/pkg/controller/suite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ var _ = BeforeSuite(func() {
7777
Expect(err).ToNot(HaveOccurred())
7878
ctx, cancel = context.WithCancel(context.Background())
7979

80-
workspaceCtrl, err = NewWorkspaceController(k8sClient, record.NewFakeRecorder(100), NodeName, secretsNamespace, 5, nil, ctrl_metrics.Registry)
80+
workspaceCtrl, err = NewWorkspaceController(k8sClient, record.NewFakeRecorder(100), NodeName, secretsNamespace, 5, nil, ctrl_metrics.Registry, nil)
8181
Expect(err).NotTo(HaveOccurred())
8282

8383
Expect(workspaceCtrl.SetupWithManager(k8sManager)).To(Succeed())

components/ws-daemon/pkg/controller/workspace_controller.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ type WorkspaceController struct {
6161
metrics *workspaceMetrics
6262
secretNamespace string
6363
recorder record.EventRecorder
64+
runtime container.Runtime
6465
}
6566

66-
func NewWorkspaceController(c client.Client, recorder record.EventRecorder, nodeName, secretNamespace string, maxConcurrentReconciles int, ops WorkspaceOperations, reg prometheus.Registerer) (*WorkspaceController, error) {
67+
func NewWorkspaceController(c client.Client, recorder record.EventRecorder, nodeName, secretNamespace string, maxConcurrentReconciles int, ops WorkspaceOperations, reg prometheus.Registerer, runtime container.Runtime) (*WorkspaceController, error) {
6768
metrics := newWorkspaceMetrics()
6869
reg.Register(metrics)
6970

@@ -75,6 +76,7 @@ func NewWorkspaceController(c client.Client, recorder record.EventRecorder, node
7576
metrics: metrics,
7677
secretNamespace: secretNamespace,
7778
recorder: recorder,
79+
runtime: runtime,
7880
}, nil
7981
}
8082

@@ -219,7 +221,30 @@ func (wsc *WorkspaceController) handleWorkspaceRunning(ctx context.Context, ws *
219221
span, ctx := opentracing.StartSpanFromContext(ctx, "handleWorkspaceRunning")
220222
defer tracing.FinishSpan(span, &err)
221223

222-
return ctrl.Result{}, wsc.operations.SetupWorkspace(ctx, ws.Name)
224+
if ws.Status.ImageInfo == nil {
225+
id, err := wsc.runtime.WaitForContainer(ctx, ws.Name)
226+
if err != nil {
227+
return ctrl.Result{}, fmt.Errorf("failed to wait for container: %w", err)
228+
}
229+
info, err := wsc.runtime.GetContainerImageInfo(ctx, id)
230+
if err != nil {
231+
return ctrl.Result{}, fmt.Errorf("failed to get container image info: %w", err)
232+
}
233+
glog.WithFields(ws.OWI()).WithField("workspace", req.NamespacedName).WithField("info", glog.TrustedValueWrap{Value: info}).WithField("phase", ws.Status.Phase).Info("handle workspace running ===============")
234+
235+
err = retry.RetryOnConflict(retryParams, func() error {
236+
if err := wsc.Get(ctx, req.NamespacedName, ws); err != nil {
237+
return err
238+
}
239+
ws.Status.ImageInfo = info
240+
return wsc.Status().Update(ctx, ws)
241+
})
242+
if err != nil {
243+
glog.WithFields(ws.OWI()).WithField("workspace", req.NamespacedName).WithField("phase", ws.Status.Phase).Errorf("failed to update workspace with image info: %v", err)
244+
}
245+
wsc.operations.SetupWorkspace(ctx, ws.Name, info)
246+
}
247+
return ctrl.Result{}, wsc.operations.SetupWorkspace(ctx, ws.Name, nil)
223248
}
224249

225250
func (wsc *WorkspaceController) handleWorkspaceStop(ctx context.Context, ws *workspacev1.Workspace, req ctrl.Request) (result ctrl.Result, err error) {

components/ws-daemon/pkg/controller/workspace_operations.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package controller
66

77
import (
88
"context"
9+
"encoding/json"
910
"errors"
1011
"fmt"
1112
"io/fs"
@@ -22,6 +23,7 @@ import (
2223
"github.com/gitpod-io/gitpod/content-service/pkg/storage"
2324
"github.com/gitpod-io/gitpod/ws-daemon/pkg/content"
2425
"github.com/gitpod-io/gitpod/ws-daemon/pkg/internal/session"
26+
workspacev1 "github.com/gitpod-io/gitpod/ws-manager/api/crd/v1"
2527
"github.com/opentracing/opentracing-go"
2628
"github.com/prometheus/client_golang/prometheus"
2729
"github.com/sirupsen/logrus"
@@ -71,7 +73,7 @@ type WorkspaceOperations interface {
7173
// Snapshot takes a snapshot of the workspace
7274
Snapshot(ctx context.Context, instanceID, snapshotName string) (err error)
7375
// Setup ensures that the workspace has been setup
74-
SetupWorkspace(ctx context.Context, instanceID string) error
76+
SetupWorkspace(ctx context.Context, instanceID string, imageInfo *workspacev1.WorkspaceImageInfo) error
7577
}
7678

7779
type DefaultWorkspaceOperations struct {
@@ -211,12 +213,15 @@ func (wso *DefaultWorkspaceOperations) creator(owner, workspaceID, instanceID st
211213
}
212214
}
213215

214-
func (wso *DefaultWorkspaceOperations) SetupWorkspace(ctx context.Context, instanceID string) error {
215-
_, err := wso.provider.GetAndConnect(ctx, instanceID)
216+
func (wso *DefaultWorkspaceOperations) SetupWorkspace(ctx context.Context, instanceID string, imageInfo *workspacev1.WorkspaceImageInfo) error {
217+
ws, err := wso.provider.GetAndConnect(ctx, instanceID)
216218
if err != nil {
217219
return fmt.Errorf("cannot setup workspace %s: %w", instanceID, err)
218220
}
219-
221+
err = wso.writeImageInfo(ctx, ws, imageInfo)
222+
if err != nil {
223+
glog.WithError(err).WithFields(ws.OWI()).Error("cannot write image info")
224+
}
220225
return nil
221226
}
222227

@@ -513,6 +518,26 @@ func (wso *DefaultWorkspaceOperations) uploadWorkspaceContent(ctx context.Contex
513518
return nil
514519
}
515520

521+
func (wso *DefaultWorkspaceOperations) writeImageInfo(_ context.Context, ws *session.Workspace, imageInfo *workspacev1.WorkspaceImageInfo) error {
522+
if imageInfo == nil {
523+
return nil
524+
}
525+
526+
b, err := json.Marshal(imageInfo)
527+
if err != nil {
528+
return fmt.Errorf("cannot marshal image info: %w", err)
529+
}
530+
uid := (wsinit.GitpodUID + 100000 - 1)
531+
gid := (wsinit.GitpodGID + 100000 - 1)
532+
fp := filepath.Join(ws.Location, ".gitpod/image")
533+
err = os.WriteFile(fp, b, 0644)
534+
if err != nil {
535+
return fmt.Errorf("cannot write image info: %w", err)
536+
}
537+
os.Chown(fp, uid, gid)
538+
return nil
539+
}
540+
516541
func retryIfErr(ctx context.Context, attempts int, log *logrus.Entry, op func(ctx context.Context) error) (err error) {
517542
//nolint:ineffassign
518543
span, ctx := opentracing.StartSpanFromContext(ctx, "retryIfErr")

components/ws-daemon/pkg/daemon/daemon.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ func NewDaemon(config Config) (*Daemon, error) {
214214
}
215215

216216
wsctrl, err := controller.NewWorkspaceController(
217-
mgr.GetClient(), mgr.GetEventRecorderFor("workspace"), nodename, config.Runtime.SecretsNamespace, config.WorkspaceController.MaxConcurrentReconciles, workspaceOps, wrappedReg)
217+
mgr.GetClient(), mgr.GetEventRecorderFor("workspace"), nodename, config.Runtime.SecretsNamespace, config.WorkspaceController.MaxConcurrentReconciles, workspaceOps, wrappedReg, containerRuntime)
218218
if err != nil {
219219
return nil, err
220220
}

components/ws-manager-api/go/crd/v1/workspace_types.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,21 @@ func (ps PortSpec) Equal(other PortSpec) bool {
168168
return true
169169
}
170170

171+
type WorkspaceImageInfo struct {
172+
// +kubebuilder:validation:Required
173+
TotalSize int64 `json:"totalSize"`
174+
175+
// +kubebuilder:validation:Optional
176+
Details []ImageInfo `json:"details"`
177+
}
178+
179+
type ImageInfo struct {
180+
// +kubebuilder:validation:Required
181+
Size int64 `json:"size"`
182+
// +kubebuilder:validation:Required
183+
Ref string `json:"ref"`
184+
}
185+
171186
// WorkspaceStatus defines the observed state of Workspace
172187
type WorkspaceStatus struct {
173188
PodStarts int `json:"podStarts"`
@@ -193,6 +208,9 @@ type WorkspaceStatus struct {
193208
Storage StorageStatus `json:"storage,omitempty"`
194209

195210
LastActivity *metav1.Time `json:"lastActivity,omitempty"`
211+
212+
// +kubebuilder:validation:Optional
213+
ImageInfo *WorkspaceImageInfo `json:"imageInfo,omitempty"`
196214
}
197215

198216
func (s *WorkspaceStatus) SetCondition(cond metav1.Condition) {

components/ws-manager-api/go/crd/v1/zz_generated.deepcopy.go

Lines changed: 40 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)