diff --git a/components/common-go/cgroups/cgroup.go b/components/common-go/cgroups/cgroup.go index c34d91e23efdef..7b460ee6ae54c3 100644 --- a/components/common-go/cgroups/cgroup.go +++ b/components/common-go/cgroups/cgroup.go @@ -5,6 +5,8 @@ package cgroups import ( + "bufio" + "fmt" "math" "os" "strconv" @@ -85,3 +87,49 @@ func ReadFlatKeyedFile(path string) (map[string]uint64, error) { return kv, nil } + +// Read the total stalled time in microseconds for full and some +// It is not necessary to read avg10, avg60 and avg300 as these +// are only for convenience. They are calculated as the rate during +// the desired time frame. +func ReadPSIValue(path string) (PSI, error) { + file, err := os.Open(path) + if err != nil { + return PSI{}, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + var psi PSI + for scanner.Scan() { + line := scanner.Text() + if err = scanner.Err(); err != nil { + return PSI{}, fmt.Errorf("could not read psi file: %w", err) + } + + i := strings.LastIndex(line, "total=") + if i == -1 { + return PSI{}, fmt.Errorf("could not find total stalled time") + } + + total, err := strconv.ParseUint(line[i+6:], 10, 64) + if err != nil { + return PSI{}, fmt.Errorf("could not parse total stalled time: %w", err) + } + + if strings.HasPrefix(line, "some") { + psi.Some = total + } + + if strings.HasPrefix(line, "full") { + psi.Full = total + } + } + + return psi, nil +} + +type PSI struct { + Some uint64 + Full uint64 +} diff --git a/components/common-go/cgroups/cgroups_test.go b/components/common-go/cgroups/cgroups_test.go index 42ea2e4dee9815..828674083e8cd0 100644 --- a/components/common-go/cgroups/cgroups_test.go +++ b/components/common-go/cgroups/cgroups_test.go @@ -134,3 +134,57 @@ func TestReadSingleValue(t *testing.T) { }) } } + +func TestReadPSI(t *testing.T) { + scenarios := []struct { + name string + content string + expected PSI + }{ + { + name: "psi some", + content: "some avg10=61.00 avg60=64.28 avg300=29.94 total=149969752", + expected: PSI{ + Some: 149969752, + Full: 0, + }, + }, + { + name: "psi full", + content: "full avg10=36.27 avg60=37.15 avg300=17.59 total=93027571", + expected: PSI{ + Some: 0, + Full: 93027571, + }, + }, + { + name: "psi some and full", + content: "some avg10=61.00 avg60=64.28 avg300=29.94 total=149969752\nfull avg10=36.27 avg60=37.15 avg300=17.59 total=93027571", + expected: PSI{ + Some: 149969752, + Full: 93027571, + }, + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + f, err := os.CreateTemp("", "cgroup_test*") + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + + if _, err := f.Write([]byte(s.content)); err != nil { + t.Fatal(err) + } + + v, err := ReadPSIValue(f.Name()) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, s.expected, v) + }) + } +} diff --git a/components/common-go/cgroups/v1/cpu.go b/components/common-go/cgroups/v1/cpu.go index d16015c04e3d25..d0910662fdbd26 100644 --- a/components/common-go/cgroups/v1/cpu.go +++ b/components/common-go/cgroups/v1/cpu.go @@ -2,7 +2,7 @@ // Licensed under the GNU Affero General Public License (AGPL). // See License-AGPL.txt in the project root for license information. -package v1 +package cgroups_v1 import ( "path/filepath" diff --git a/components/common-go/cgroups/v1/memory.go b/components/common-go/cgroups/v1/memory.go index 162a2fc4a953a4..526232be79879e 100644 --- a/components/common-go/cgroups/v1/memory.go +++ b/components/common-go/cgroups/v1/memory.go @@ -2,7 +2,7 @@ // Licensed under the GNU Affero General Public License (AGPL). // See License-AGPL.txt in the project root for license information. -package v1 +package cgroups_v1 import ( "path/filepath" diff --git a/components/common-go/cgroups/v2/cpu.go b/components/common-go/cgroups/v2/cpu.go index 849f87a52a170a..4881be66d908b4 100644 --- a/components/common-go/cgroups/v2/cpu.go +++ b/components/common-go/cgroups/v2/cpu.go @@ -2,7 +2,7 @@ // Licensed under the GNU Affero General Public License (AGPL). // See License-AGPL.txt in the project root for license information. -package v2 +package cgroups_v2 import ( "math" @@ -84,3 +84,8 @@ func (c *Cpu) Stat() (*cgroups.CpuStats, error) { return &stats, nil } + +func (c *Cpu) PSI() (cgroups.PSI, error) { + path := filepath.Join(c.path, "cpu.pressure") + return cgroups.ReadPSIValue(path) +} diff --git a/components/common-go/cgroups/v2/cpu_test.go b/components/common-go/cgroups/v2/cpu_test.go index feef1ed6b291bc..a3b4a82a82b254 100644 --- a/components/common-go/cgroups/v2/cpu_test.go +++ b/components/common-go/cgroups/v2/cpu_test.go @@ -2,7 +2,7 @@ // Licensed under the GNU Affero General Public License (AGPL). // See License-AGPL.txt in the project root for license information. -package v2 +package cgroups_v2 import ( "fmt" diff --git a/components/common-go/cgroups/v2/io.go b/components/common-go/cgroups/v2/io.go new file mode 100644 index 00000000000000..fa8d15941f76dd --- /dev/null +++ b/components/common-go/cgroups/v2/io.go @@ -0,0 +1,33 @@ +// Copyright (c) 2022 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package cgroups_v2 + +import ( + "path/filepath" + + "github.com/gitpod-io/gitpod/common-go/cgroups" +) + +type IO struct { + path string +} + +func NewIOControllerWithMount(mountPoint, path string) *IO { + fullPath := filepath.Join(mountPoint, path) + return &IO{ + path: fullPath, + } +} + +func NewIOController(path string) *IO { + return &IO{ + path: path, + } +} + +func (io *IO) PSI() (cgroups.PSI, error) { + path := filepath.Join(io.path, "io.pressure") + return cgroups.ReadPSIValue(path) +} diff --git a/components/common-go/cgroups/v2/memory.go b/components/common-go/cgroups/v2/memory.go index 37d96f113840b8..6d9730b1559b14 100644 --- a/components/common-go/cgroups/v2/memory.go +++ b/components/common-go/cgroups/v2/memory.go @@ -2,7 +2,7 @@ // Licensed under the GNU Affero General Public License (AGPL). // See License-AGPL.txt in the project root for license information. -package v2 +package cgroups_v2 import ( "path/filepath" @@ -63,3 +63,8 @@ func (m *Memory) Stat() (*cgroups.MemoryStats, error) { InactiveFileTotal: statMap["inactive_file"], }, nil } + +func (m *Memory) PSI() (cgroups.PSI, error) { + path := filepath.Join(m.path, "memory.pressure") + return cgroups.ReadPSIValue(path) +} diff --git a/components/common-go/kubernetes/kubernetes.go b/components/common-go/kubernetes/kubernetes.go index e3066d2cf52a28..6a677ae9f96714 100644 --- a/components/common-go/kubernetes/kubernetes.go +++ b/components/common-go/kubernetes/kubernetes.go @@ -72,6 +72,9 @@ const ( // workspaceNetConnLimit denotes the maximum number of connections a workspace can make per minute WorkspaceNetConnLimitAnnotation = "gitpod.io/netConnLimitPerMinute" + + // workspacePressureStallInfo indicates if pressure stall information should be retrieved for the workspace + WorkspacePressureStallInfoAnnotation = "gitpod.io/psi" ) // GetOWIFromObject finds the owner, workspace and instance information on a Kubernetes object using labels diff --git a/components/gitpod-protocol/src/protocol.ts b/components/gitpod-protocol/src/protocol.ts index 3e97767421e660..b4af9a957e66b0 100644 --- a/components/gitpod-protocol/src/protocol.ts +++ b/components/gitpod-protocol/src/protocol.ts @@ -298,6 +298,7 @@ export const WorkspaceFeatureFlags = { protected_secrets: undefined, workspace_class_limiting: undefined, workspace_connection_limiting: undefined, + workspace_psi: undefined, }; export type NamedWorkspaceFeatureFlag = keyof typeof WorkspaceFeatureFlags; export namespace NamedWorkspaceFeatureFlag { diff --git a/components/server/src/workspace/workspace-starter.ts b/components/server/src/workspace/workspace-starter.ts index 5ef76ec160892e..edfb27be1c81c5 100644 --- a/components/server/src/workspace/workspace-starter.ts +++ b/components/server/src/workspace/workspace-starter.ts @@ -59,6 +59,7 @@ import { IDESettings, WithReferrerContext, EnvVarWithValue, + BillingTier, } from "@gitpod/gitpod-protocol"; import { IAnalyticsWriter } from "@gitpod/gitpod-protocol/lib/analytics"; import { log } from "@gitpod/gitpod-protocol/lib/util/logging"; @@ -849,37 +850,12 @@ export class WorkspaceStarter { ); } - if ( - await getExperimentsClientForBackend().getValueAsync("protected_secrets", false, { - user, - billingTier, - }) - ) { - // We roll out the protected secrets feature using a ConfigCat feature flag, to ensure - // a smooth, gradual roll out without breaking users. - featureFlags = featureFlags.concat(["protected_secrets"]); - } + await this.tryEnableProtectedSecrets(featureFlags, user, billingTier); featureFlags = featureFlags.filter((f) => !excludeFeatureFlags.includes(f)); - const wsConnectionLimitingEnabled = await getExperimentsClientForBackend().getValueAsync( - "workspace_connection_limiting", - false, - { - user, - billingTier, - }, - ); - - if (wsConnectionLimitingEnabled) { - const shouldLimitNetworkConnections = await this.entitlementService.limitNetworkConnections( - user, - new Date(), - ); - if (shouldLimitNetworkConnections) { - featureFlags = featureFlags.concat(["workspace_connection_limiting"]); - } - } + await this.tryEnableConnectionLimiting(featureFlags, user, billingTier); + await this.tryEnablePSI(featureFlags, user, billingTier); const usageAttributionId = await this.userService.getWorkspaceUsageAttributionId(user, workspace.projectId); const billingMode = await this.billingModes.getBillingMode(usageAttributionId, new Date()); @@ -965,6 +941,59 @@ export class WorkspaceStarter { } } + private async tryEnableProtectedSecrets( + featureFlags: NamedWorkspaceFeatureFlag[], + user: User, + billingTier: BillingTier, + ) { + if ( + await getExperimentsClientForBackend().getValueAsync("protected_secrets", false, { + user, + billingTier, + }) + ) { + // We roll out the protected secrets feature using a ConfigCat feature flag, to ensure + // a smooth, gradual roll out without breaking users. + featureFlags.push("protected_secrets"); + } + } + + private async tryEnableConnectionLimiting( + featureFlags: NamedWorkspaceFeatureFlag[], + user: User, + billingTier: BillingTier, + ) { + const wsConnectionLimitingEnabled = await getExperimentsClientForBackend().getValueAsync( + "workspace_connection_limiting", + false, + { + user, + billingTier, + }, + ); + + if (wsConnectionLimitingEnabled) { + const shouldLimitNetworkConnections = await this.entitlementService.limitNetworkConnections( + user, + new Date(), + ); + if (shouldLimitNetworkConnections) { + featureFlags.push("workspace_connection_limiting"); + } + } + } + + private async tryEnablePSI(featureFlags: NamedWorkspaceFeatureFlag[], user: User, billingTier: BillingTier) { + const psiEnabled = await getExperimentsClientForBackend().getValueAsync("pressure_stall_info", false, { + user, + billingTier, + }); + + if (psiEnabled && billingTier === "paid") { + featureFlags.push("workspace_psi"); + } + } + // TODO(ak) move to IDE service protected resolveReferrerIDE( workspace: Workspace, diff --git a/components/ws-daemon/pkg/cgroup/cgroup.go b/components/ws-daemon/pkg/cgroup/cgroup.go index 27c198262e5627..bea3a6ca986385 100644 --- a/components/ws-daemon/pkg/cgroup/cgroup.go +++ b/components/ws-daemon/pkg/cgroup/cgroup.go @@ -84,13 +84,20 @@ func (host *PluginHost) WorkspaceAdded(ctx context.Context, ws *dispatch.Workspa return xerrors.Errorf("cannot get cgroup path for container %s: %w", ws.ContainerID, err) } + opts := &PluginOptions{ + BasePath: host.CGroupBasePath, + CgroupPath: cgroupPath, + InstanceId: ws.InstanceID, + Annotations: ws.Pod.Annotations, + } + for _, plg := range host.Plugins { if plg.Type() != host.CGroupVersion { continue } go func(plg Plugin) { - err := plg.Apply(ctx, host.CGroupBasePath, cgroupPath) + err := plg.Apply(ctx, opts) if err == context.Canceled || err == context.DeadlineExceeded { err = nil } @@ -109,7 +116,7 @@ func (host *PluginHost) WorkspaceAdded(ctx context.Context, ws *dispatch.Workspa type Plugin interface { Name() string Type() Version - Apply(ctx context.Context, basePath, cgroupPath string) error + Apply(ctx context.Context, options *PluginOptions) error } type Version int @@ -118,3 +125,10 @@ const ( Version1 Version = iota Version2 ) + +type PluginOptions struct { + BasePath string + CgroupPath string + InstanceId string + Annotations map[string]string +} diff --git a/components/ws-daemon/pkg/cgroup/plugin_cachereclaim.go b/components/ws-daemon/pkg/cgroup/plugin_cachereclaim.go index c732c15c3de80b..365f360fd23331 100644 --- a/components/ws-daemon/pkg/cgroup/plugin_cachereclaim.go +++ b/components/ws-daemon/pkg/cgroup/plugin_cachereclaim.go @@ -25,8 +25,8 @@ type CacheReclaim struct{} func (c *CacheReclaim) Name() string { return "cache-reclaim-v1" } func (c *CacheReclaim) Type() Version { return Version1 } -func (c *CacheReclaim) Apply(ctx context.Context, basePath, cgroupPath string) error { - memPath := filepath.Join(string(basePath), "memory", cgroupPath) +func (c *CacheReclaim) Apply(ctx context.Context, opts *PluginOptions) error { + memPath := filepath.Join(string(opts.BasePath), "memory", opts.CgroupPath) t := time.NewTicker(10 * time.Second) defer t.Stop() diff --git a/components/ws-daemon/pkg/cgroup/plugin_fuse.go b/components/ws-daemon/pkg/cgroup/plugin_fuse.go index f58879802c0c02..4009ece56163e9 100644 --- a/components/ws-daemon/pkg/cgroup/plugin_fuse.go +++ b/components/ws-daemon/pkg/cgroup/plugin_fuse.go @@ -22,11 +22,11 @@ type FuseDeviceEnablerV1 struct{} func (c *FuseDeviceEnablerV1) Name() string { return "fuse-device-enabler-v1" } func (c *FuseDeviceEnablerV1) Type() Version { return Version1 } -func (c *FuseDeviceEnablerV1) Apply(ctx context.Context, basePath, cgroupPath string) error { - control, err := cgroups.Load(customV1(basePath), cgroups.StaticPath(cgroupPath)) +func (c *FuseDeviceEnablerV1) Apply(ctx context.Context, opts *PluginOptions) error { + control, err := cgroups.Load(customV1(opts.BasePath), cgroups.StaticPath(opts.CgroupPath)) if err != nil { - return xerrors.Errorf("error loading cgroup at path: %s %w", cgroupPath, err) + return xerrors.Errorf("error loading cgroup at path: %s %w", opts.CgroupPath, err) } res := &specs.LinuxResources{ diff --git a/components/ws-daemon/pkg/cgroup/plugin_fuse_v2.go b/components/ws-daemon/pkg/cgroup/plugin_fuse_v2.go index b37129e4731ef7..0ce2d2e4894623 100644 --- a/components/ws-daemon/pkg/cgroup/plugin_fuse_v2.go +++ b/components/ws-daemon/pkg/cgroup/plugin_fuse_v2.go @@ -23,8 +23,8 @@ type FuseDeviceEnablerV2 struct{} func (c *FuseDeviceEnablerV2) Name() string { return "fuse-device-enabler-v2" } func (c *FuseDeviceEnablerV2) Type() Version { return Version2 } -func (c *FuseDeviceEnablerV2) Apply(ctx context.Context, basePath, cgroupPath string) error { - fullCgroupPath := filepath.Join(basePath, cgroupPath) +func (c *FuseDeviceEnablerV2) Apply(ctx context.Context, opts *PluginOptions) error { + fullCgroupPath := filepath.Join(opts.BasePath, opts.CgroupPath) log.WithField("cgroupPath", fullCgroupPath).Debug("configuring devices") cgroupFD, err := unix.Open(fullCgroupPath, unix.O_DIRECTORY|unix.O_RDONLY|unix.O_CLOEXEC, 0600) diff --git a/components/ws-daemon/pkg/cgroup/plugin_iolimit_v1.go b/components/ws-daemon/pkg/cgroup/plugin_iolimit_v1.go index 485ae27fe5a9bf..3cf93ab15a23b1 100644 --- a/components/ws-daemon/pkg/cgroup/plugin_iolimit_v1.go +++ b/components/ws-daemon/pkg/cgroup/plugin_iolimit_v1.go @@ -82,8 +82,8 @@ func (c *IOLimiterV1) Update(writeBytesPerSecond, readBytesPerSecond, writeIOPs, c.cond.Broadcast() } -func (c *IOLimiterV1) Apply(ctx context.Context, basePath, cgroupPath string) error { - baseCgroupPath := filepath.Join(basePath, "blkio", cgroupPath) +func (c *IOLimiterV1) Apply(ctx context.Context, opts *PluginOptions) error { + baseCgroupPath := filepath.Join(opts.BasePath, "blkio", opts.CgroupPath) writeLimits := func(l ioLimitOptions, fromCache bool) error { err := writeLimit(filepath.Join(baseCgroupPath, fnBlkioThrottleWriteBps), c.produceLimits(fnBlkioThrottleWriteBps, l.WriteBytesPerSecond, fromCache)) @@ -123,19 +123,19 @@ func (c *IOLimiterV1) Apply(ctx context.Context, basePath, cgroupPath string) er }() go func() { - log.WithField("cgroupPath", cgroupPath).Debug("starting IO limiting") + log.WithField("cgroupPath", opts.CgroupPath).Debug("starting IO limiting") err := writeLimits(c.limits, false) if err != nil { - log.WithError(err).WithField("cgroupPath", cgroupPath).Error("cannot write IO limits") + log.WithError(err).WithField("cgroupPath", opts.CgroupPath).Error("cannot write IO limits") } for { select { case <-update: - log.WithField("cgroupPath", cgroupPath).WithField("l", c.limits).Debug("writing new IO limiting") + log.WithField("cgroupPath", opts.CgroupPath).WithField("l", c.limits).Debug("writing new IO limiting") err := writeLimits(c.limits, false) if err != nil { - log.WithError(err).WithField("cgroupPath", cgroupPath).Error("cannot write IO limits") + log.WithError(err).WithField("cgroupPath", opts.CgroupPath).Error("cannot write IO limits") } case <-ctx.Done(): // Prior to shutting down though, we need to reset the IO limits to ensure we don't have @@ -143,9 +143,9 @@ func (c *IOLimiterV1) Apply(ctx context.Context, basePath, cgroupPath string) er // workspace pod from shutting down. err = writeLimits(ioLimitOptions{}, false) if err != nil { - log.WithError(err).WithField("cgroupPath", cgroupPath).Error("cannot reset IO limits") + log.WithError(err).WithField("cgroupPath", opts.CgroupPath).Error("cannot reset IO limits") } - log.WithField("cgroupPath", cgroupPath).Debug("stopping IO limiting") + log.WithField("cgroupPath", opts.CgroupPath).Debug("stopping IO limiting") return } } diff --git a/components/ws-daemon/pkg/cgroup/plugin_iolimit_v2.go b/components/ws-daemon/pkg/cgroup/plugin_iolimit_v2.go index e668c9f3b819a6..6fbcb18434f1ab 100644 --- a/components/ws-daemon/pkg/cgroup/plugin_iolimit_v2.go +++ b/components/ws-daemon/pkg/cgroup/plugin_iolimit_v2.go @@ -37,7 +37,7 @@ func NewIOLimiterV2(writeBytesPerSecond, readBytesPerSecond, writeIOPs, readIOPs func (c *IOLimiterV2) Name() string { return "iolimiter-v2" } func (c *IOLimiterV2) Type() Version { return Version2 } -func (c *IOLimiterV2) Apply(ctx context.Context, basePath, cgroupPath string) error { +func (c *IOLimiterV2) Apply(ctx context.Context, opts *PluginOptions) error { update := make(chan struct{}, 1) go func() { // TODO(cw): this Go-routine will leak per workspace, until we update config or restart ws-daemon @@ -57,29 +57,29 @@ func (c *IOLimiterV2) Apply(ctx context.Context, basePath, cgroupPath string) er }() go func() { - log.WithField("cgroupPath", cgroupPath).Debug("starting io limiting") + log.WithField("cgroupPath", opts.CgroupPath).Debug("starting io limiting") - _, err := v2.NewManager(basePath, filepath.Join("/", cgroupPath), c.limits) + _, err := v2.NewManager(opts.BasePath, filepath.Join("/", opts.CgroupPath), c.limits) if err != nil { - log.WithError(err).WithField("basePath", basePath).WithField("cgroupPath", cgroupPath).WithField("limits", c.limits).Error("cannot write IO limits") + log.WithError(err).WithField("basePath", opts.BasePath).WithField("cgroupPath", opts.CgroupPath).WithField("limits", c.limits).Error("cannot write IO limits") } for { select { case <-update: - _, err := v2.NewManager(basePath, filepath.Join("/", cgroupPath), c.limits) + _, err := v2.NewManager(opts.BasePath, filepath.Join("/", opts.CgroupPath), c.limits) if err != nil { - log.WithError(err).WithField("basePath", basePath).WithField("cgroupPath", cgroupPath).WithField("limits", c.limits).Error("cannot write IO limits") + log.WithError(err).WithField("basePath", opts.BasePath).WithField("cgroupPath", opts.CgroupPath).WithField("limits", c.limits).Error("cannot write IO limits") } case <-ctx.Done(): // Prior to shutting down though, we need to reset the IO limits to ensure we don't have // processes stuck in the uninterruptable "D" (disk sleep) state. This would prevent the // workspace pod from shutting down. - _, err := v2.NewManager(basePath, filepath.Join("/", cgroupPath), &v2.Resources{}) + _, err := v2.NewManager(opts.BasePath, filepath.Join("/", opts.CgroupPath), &v2.Resources{}) if err != nil { - log.WithError(err).WithField("cgroupPath", cgroupPath).Error("cannot write IO limits") + log.WithError(err).WithField("cgroupPath", opts.CgroupPath).Error("cannot write IO limits") } - log.WithField("cgroupPath", cgroupPath).Debug("stopping io limiting") + log.WithField("cgroupPath", opts.CgroupPath).Debug("stopping io limiting") return } } diff --git a/components/ws-daemon/pkg/cgroup/plugin_proc_limit_v2.go b/components/ws-daemon/pkg/cgroup/plugin_proc_limit_v2.go index 021051062e861c..bb450c308da57c 100644 --- a/components/ws-daemon/pkg/cgroup/plugin_proc_limit_v2.go +++ b/components/ws-daemon/pkg/cgroup/plugin_proc_limit_v2.go @@ -34,7 +34,7 @@ func NewProcLimiterV2(processes int64) (*ProcLimiterV2, error) { func (c *ProcLimiterV2) Name() string { return "proc-limiter-v2" } func (c *ProcLimiterV2) Type() Version { return Version2 } -func (c *ProcLimiterV2) Apply(ctx context.Context, basePath, cgroupPath string) error { +func (c *ProcLimiterV2) Apply(ctx context.Context, opts *PluginOptions) error { update := make(chan struct{}, 1) go func() { defer close(update) @@ -53,19 +53,19 @@ func (c *ProcLimiterV2) Apply(ctx context.Context, basePath, cgroupPath string) }() go func() { - log.WithField("cgroupPath", cgroupPath).Debug("starting proc limiting") + log.WithField("cgroupPath", opts.CgroupPath).Debug("starting proc limiting") - _, err := v2.NewManager(basePath, filepath.Join("/", cgroupPath), c.limits) + _, err := v2.NewManager(opts.BasePath, filepath.Join("/", opts.CgroupPath), c.limits) if err != nil { - log.WithError(err).WithField("basePath", basePath).WithField("cgroupPath", cgroupPath).WithField("limits", c.limits).Error("cannot write proc limits") + log.WithError(err).WithField("basePath", opts.BasePath).WithField("cgroupPath", opts.CgroupPath).WithField("limits", c.limits).Error("cannot write proc limits") } for { select { case <-update: - _, err := v2.NewManager(basePath, filepath.Join("/", cgroupPath), c.limits) + _, err := v2.NewManager(opts.BasePath, filepath.Join("/", opts.CgroupPath), c.limits) if err != nil { - log.WithError(err).WithField("basePath", basePath).WithField("cgroupPath", cgroupPath).WithField("limits", c.limits).Error("cannot write proc limits") + log.WithError(err).WithField("basePath", opts.BasePath).WithField("cgroupPath", opts.CgroupPath).WithField("limits", c.limits).Error("cannot write proc limits") } case <-ctx.Done(): return diff --git a/components/ws-daemon/pkg/cgroup/plugin_process_priority_v2.go b/components/ws-daemon/pkg/cgroup/plugin_process_priority_v2.go index f63228105a64b9..d6a2178b1a6652 100644 --- a/components/ws-daemon/pkg/cgroup/plugin_process_priority_v2.go +++ b/components/ws-daemon/pkg/cgroup/plugin_process_priority_v2.go @@ -48,8 +48,8 @@ type ProcessPriorityV2 struct { func (c *ProcessPriorityV2) Name() string { return "process-priority-v2" } func (c *ProcessPriorityV2) Type() Version { return Version2 } -func (c *ProcessPriorityV2) Apply(ctx context.Context, basePath, cgroupPath string) error { - fullCgroupPath := filepath.Join(basePath, cgroupPath) +func (c *ProcessPriorityV2) Apply(ctx context.Context, opts *PluginOptions) error { + fullCgroupPath := filepath.Join(opts.BasePath, opts.CgroupPath) _, err := os.Stat(fullCgroupPath) if errors.Is(err, fs.ErrNotExist) { diff --git a/components/ws-daemon/pkg/cgroup/plugin_psi.go b/components/ws-daemon/pkg/cgroup/plugin_psi.go new file mode 100644 index 00000000000000..cf0f455799b827 --- /dev/null +++ b/components/ws-daemon/pkg/cgroup/plugin_psi.go @@ -0,0 +1,110 @@ +// Copyright (c) 2022 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package cgroup + +import ( + "context" + "os" + "path/filepath" + "time" + + cgroups "github.com/gitpod-io/gitpod/common-go/cgroups/v2" + "github.com/gitpod-io/gitpod/common-go/kubernetes" + "github.com/gitpod-io/gitpod/common-go/log" + "github.com/prometheus/client_golang/prometheus" +) + +type PSIMetrics struct { + cpu *prometheus.GaugeVec + memory *prometheus.GaugeVec + io *prometheus.GaugeVec + nodeName string +} + +func NewPSIMetrics(prom prometheus.Registerer) *PSIMetrics { + p := &PSIMetrics{ + cpu: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "workspace_cpu_psi_total_seconds", + Help: "Total time spent under cpu pressure in microseconds", + }, []string{"node", "workspace", "kind"}), + + memory: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "workspace_memory_psi_total_seconds", + Help: "Total time spent under memory pressure in microseconds", + }, []string{"node", "workspace", "kind"}), + + io: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "workspace_io_psi_total_seconds", + Help: "Total time spent under io pressure in microseconds", + }, []string{"node", "workspace", "kind"}), + + nodeName: os.Getenv("NODENAME"), + } + + prom.MustRegister( + p.cpu, + p.memory, + p.io, + ) + + return p +} + +func (p *PSIMetrics) Name() string { return "psi-metrics" } +func (p *PSIMetrics) Type() Version { return Version2 } + +func (p *PSIMetrics) Apply(ctx context.Context, opts *PluginOptions) error { + if _, v := opts.Annotations[kubernetes.WorkspacePressureStallInfoAnnotation]; !v { + return nil + } + + fullPath := filepath.Join(opts.BasePath, opts.CgroupPath) + if _, err := os.Stat(fullPath); err != nil { + return err + } + + cpu := cgroups.NewCpuController(fullPath) + memory := cgroups.NewMemoryController(fullPath) + io := cgroups.NewIOController(fullPath) + + go func() { + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + p.scrape(cpu, memory, io, opts.InstanceId) + case <-ctx.Done(): + return + } + } + }() + + return nil +} + +func (p *PSIMetrics) scrape(cpu *cgroups.Cpu, memory *cgroups.Memory, io *cgroups.IO, instanceID string) { + if psi, err := cpu.PSI(); err == nil { + p.cpu.WithLabelValues(p.nodeName, instanceID, "some").Set(float64(psi.Some)) + p.cpu.WithLabelValues(p.nodeName, instanceID, "full").Set(float64(psi.Full)) + } else if !os.IsNotExist(err) { + log.WithError(err).Warn("could not retrieve cpu psi") + } + + if psi, err := memory.PSI(); err == nil { + p.memory.WithLabelValues(p.nodeName, instanceID, "some").Set(float64(psi.Some)) + p.memory.WithLabelValues(p.nodeName, instanceID, "full").Set(float64(psi.Full)) + } else if !os.IsNotExist(err) { + log.WithError(err).Warn("could not retrieve memory psi") + } + + if psi, err := io.PSI(); err == nil { + p.io.WithLabelValues(p.nodeName, instanceID, "some").Set(float64(psi.Some)) + p.io.WithLabelValues(p.nodeName, instanceID, "full").Set(float64(psi.Full)) + } else if !os.IsNotExist(err) { + log.WithError(err).Warn("could not retrieve io psi") + } +} diff --git a/components/ws-daemon/pkg/daemon/daemon.go b/components/ws-daemon/pkg/daemon/daemon.go index 5fbea844cab42a..83da32e561401f 100644 --- a/components/ws-daemon/pkg/daemon/daemon.go +++ b/components/ws-daemon/pkg/daemon/daemon.go @@ -87,6 +87,7 @@ func NewDaemon(config Config, reg prometheus.Registerer) (*Daemon, error) { }, }, procV2Plugin, + cgroup.NewPSIMetrics(reg), ) if err != nil { return nil, err diff --git a/components/ws-manager-api/core.proto b/components/ws-manager-api/core.proto index b30a1fbe792856..f5afd4c0366d03 100644 --- a/components/ws-manager-api/core.proto +++ b/components/ws-manager-api/core.proto @@ -620,6 +620,9 @@ enum WorkspaceFeatureFlag { // WORKSPACE_CONNECTION_LIMITING feature flag for enabling network connection rate limiting WORKSPACE_CONNECTION_LIMITING = 10; + + // WORKSPACE_PSI feature flag for enabling pressure stall information for workspaces + WORKSPACE_PSI = 11; } // GitSpec configures the Git available within the workspace diff --git a/components/ws-manager-api/go/core.pb.go b/components/ws-manager-api/go/core.pb.go index 831ddd10365fcf..84893f06fa4ccd 100644 --- a/components/ws-manager-api/go/core.pb.go +++ b/components/ws-manager-api/go/core.pb.go @@ -325,6 +325,8 @@ const ( WorkspaceFeatureFlag_WORKSPACE_CLASS_LIMITING WorkspaceFeatureFlag = 9 // WORKSPACE_CONNECTION_LIMITING feature flag for enabling network connection rate limiting WorkspaceFeatureFlag_WORKSPACE_CONNECTION_LIMITING WorkspaceFeatureFlag = 10 + // WORKSPACE_PSI feature flag for enabling pressure stall information for workspaces + WorkspaceFeatureFlag_WORKSPACE_PSI WorkspaceFeatureFlag = 11 ) // Enum value maps for WorkspaceFeatureFlag. @@ -336,6 +338,7 @@ var ( 8: "PROTECTED_SECRETS", 9: "WORKSPACE_CLASS_LIMITING", 10: "WORKSPACE_CONNECTION_LIMITING", + 11: "WORKSPACE_PSI", } WorkspaceFeatureFlag_value = map[string]int32{ "NOOP": 0, @@ -344,6 +347,7 @@ var ( "PROTECTED_SECRETS": 8, "WORKSPACE_CLASS_LIMITING": 9, "WORKSPACE_CONNECTION_LIMITING": 10, + "WORKSPACE_PSI": 11, } ) @@ -3715,7 +3719,7 @@ var file_core_proto_rawDesc = []byte{ 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x52, 0x55, 0x50, 0x54, 0x45, 0x44, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, - 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x06, 0x2a, 0xce, + 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x06, 0x2a, 0xe1, 0x01, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x55, 0x4c, 0x4c, 0x5f, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, @@ -3727,87 +3731,88 @@ var file_core_proto_rawDesc = []byte{ 0x41, 0x53, 0x53, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x09, 0x12, 0x21, 0x0a, 0x1d, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x10, - 0x0a, 0x22, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x04, 0x08, 0x02, 0x10, 0x02, 0x22, 0x04, 0x08, - 0x03, 0x10, 0x03, 0x22, 0x04, 0x08, 0x05, 0x10, 0x05, 0x22, 0x04, 0x08, 0x06, 0x10, 0x06, 0x2a, - 0x46, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x47, 0x55, 0x4c, 0x41, 0x52, 0x10, 0x00, 0x12, 0x0c, 0x0a, - 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x49, - 0x4d, 0x41, 0x47, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x10, 0x04, 0x22, 0x04, 0x08, 0x02, 0x10, - 0x02, 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x32, 0xe7, 0x08, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x4c, 0x0a, 0x0d, - 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x2e, + 0x0a, 0x12, 0x11, 0x0a, 0x0d, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x50, + 0x53, 0x49, 0x10, 0x0b, 0x22, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x04, 0x08, 0x02, 0x10, 0x02, + 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x22, 0x04, 0x08, 0x05, 0x10, 0x05, 0x22, 0x04, 0x08, 0x06, + 0x10, 0x06, 0x2a, 0x46, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x47, 0x55, 0x4c, 0x41, 0x52, 0x10, 0x00, + 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x10, 0x01, 0x12, 0x0e, + 0x0a, 0x0a, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x10, 0x04, 0x22, 0x04, + 0x08, 0x02, 0x10, 0x02, 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x32, 0xe7, 0x08, 0x0a, 0x10, 0x57, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, + 0x4c, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, + 0x12, 0x1b, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x77, 0x73, 0x6d, - 0x61, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0e, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x77, - 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x73, 0x6d, - 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0d, 0x53, - 0x74, 0x6f, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x77, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, + 0x0e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, + 0x1c, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, + 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, + 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, + 0x1b, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x57, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x77, 0x73, 0x6d, 0x61, - 0x6e, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x11, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x62, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1f, - 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x57, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x12, 0x17, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, - 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x43, 0x0a, 0x0a, 0x4d, - 0x61, 0x72, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x18, 0x2e, 0x77, 0x73, 0x6d, 0x61, - 0x6e, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x61, 0x72, 0x6b, - 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x43, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x18, - 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, - 0x2e, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1a, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, - 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, - 0x0c, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1a, 0x2e, - 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, - 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x73, 0x6d, 0x61, - 0x6e, 0x2e, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x77, - 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, - 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x61, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x22, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x77, 0x73, - 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, - 0x65, 0x79, 0x12, 0x1a, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, - 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, - 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, - 0x0f, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x12, 0x1d, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1e, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, - 0x2f, 0x77, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x11, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x12, 0x1f, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x2e, 0x77, 0x73, 0x6d, 0x61, + 0x6e, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, + 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x09, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x17, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x43, + 0x0a, 0x0a, 0x4d, 0x61, 0x72, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x18, 0x2e, 0x77, + 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, + 0x61, 0x72, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, + 0x74, 0x12, 0x18, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x77, 0x73, + 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x49, 0x0a, 0x0c, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x12, 0x1a, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, + 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, + 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x10, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x1e, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, + 0x64, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1f, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, + 0x64, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x61, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, + 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x22, 0x2e, 0x77, 0x73, 0x6d, + 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, + 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x53, 0x48, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x52, 0x0a, 0x0f, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x12, 0x1d, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, + 0x70, 0x6f, 0x64, 0x2f, 0x77, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x61, + 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/components/ws-manager-api/typescript/src/core_pb.d.ts b/components/ws-manager-api/typescript/src/core_pb.d.ts index f7af61274cacd1..f02c6be2fa42f2 100644 --- a/components/ws-manager-api/typescript/src/core_pb.d.ts +++ b/components/ws-manager-api/typescript/src/core_pb.d.ts @@ -1285,6 +1285,7 @@ export enum WorkspaceFeatureFlag { PROTECTED_SECRETS = 8, WORKSPACE_CLASS_LIMITING = 9, WORKSPACE_CONNECTION_LIMITING = 10, + WORKSPACE_PSI = 11, } export enum WorkspaceType { diff --git a/components/ws-manager-api/typescript/src/core_pb.js b/components/ws-manager-api/typescript/src/core_pb.js index 79998a53714dae..256cdfc1ba3261 100644 --- a/components/ws-manager-api/typescript/src/core_pb.js +++ b/components/ws-manager-api/typescript/src/core_pb.js @@ -10019,7 +10019,8 @@ proto.wsman.WorkspaceFeatureFlag = { PERSISTENT_VOLUME_CLAIM: 7, PROTECTED_SECRETS: 8, WORKSPACE_CLASS_LIMITING: 9, - WORKSPACE_CONNECTION_LIMITING: 10 + WORKSPACE_CONNECTION_LIMITING: 10, + WORKSPACE_PSI: 11 }; /** diff --git a/components/ws-manager/pkg/manager/create.go b/components/ws-manager/pkg/manager/create.go index 8c9f6c38c98ae5..9df292831e332d 100644 --- a/components/ws-manager/pkg/manager/create.go +++ b/components/ws-manager/pkg/manager/create.go @@ -626,6 +626,9 @@ func (m *Manager) createDefiniteWorkspacePod(startContext *startWorkspaceContext case api.WorkspaceFeatureFlag_WORKSPACE_CONNECTION_LIMITING: annotations[kubernetes.WorkspaceNetConnLimitAnnotation] = util.BooleanTrueString + case api.WorkspaceFeatureFlag_WORKSPACE_PSI: + annotations[kubernetes.WorkspacePressureStallInfoAnnotation] = util.BooleanTrueString + default: log.Warnf("Unknown feature flag %v", feature) }