Path: blob/main/components/ws-daemon/pkg/cgroup/cgroup.go
2499 views
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package cgroup56import (7"context"8"errors"910"github.com/gitpod-io/gitpod/common-go/cgroups"11"github.com/gitpod-io/gitpod/common-go/log"12"github.com/gitpod-io/gitpod/ws-daemon/pkg/dispatch"13"github.com/prometheus/client_golang/prometheus"14"golang.org/x/xerrors"15)1617func NewPluginHost(cgroupBasePath string, plugins ...Plugin) (*PluginHost, error) {18var version Version19unified, err := cgroups.IsUnifiedCgroupSetup()20if err != nil {21return nil, xerrors.Errorf("could not determine cgroup setup: %w", err)22}23if unified {24version = Version225} else {26version = Version127}2829return &PluginHost{30CGroupBasePath: cgroupBasePath,31CGroupVersion: version,32Plugins: plugins,3334pluginActivationTotalVec: prometheus.NewCounterVec(prometheus.CounterOpts{35Name: "cgroup_plugin_activation_total",36Help: "counts the total activation of cgroup plugins",37}, []string{"plugin", "success"}),38}, nil39}4041type PluginHost struct {42CGroupBasePath string43CGroupVersion Version44Plugins []Plugin4546pluginActivationTotalVec *prometheus.CounterVec47}4849var _ dispatch.Listener = &PluginHost{}50var _ prometheus.Collector = &PluginHost{}5152func (host *PluginHost) Describe(c chan<- *prometheus.Desc) {53host.pluginActivationTotalVec.Describe(c)54for _, p := range host.Plugins {55col, ok := p.(prometheus.Collector)56if !ok {57continue58}5960col.Describe(c)61}62}6364func (host *PluginHost) Collect(c chan<- prometheus.Metric) {65host.pluginActivationTotalVec.Collect(c)66for _, p := range host.Plugins {67col, ok := p.(prometheus.Collector)68if !ok {69continue70}7172col.Collect(c)73}74}7576func (host *PluginHost) WorkspaceAdded(ctx context.Context, ws *dispatch.Workspace) (err error) {77disp := dispatch.GetFromContext(ctx)78if disp == nil {79return xerrors.Errorf("no dispatch available")80}8182cgroupPath, err := disp.Runtime.ContainerCGroupPath(ctx, ws.ContainerID)83if err != nil {84if errors.Is(err, context.Canceled) {85return nil86}87return xerrors.Errorf("cannot get cgroup path for container %s: %w", ws.ContainerID, err)88}8990opts := &PluginOptions{91BasePath: host.CGroupBasePath,92CgroupPath: cgroupPath,93InstanceId: ws.InstanceID,94Annotations: ws.Pod.Annotations,95}9697for _, plg := range host.Plugins {98if plg.Type() != host.CGroupVersion {99continue100}101dispatch.GetDispatchWaitGroup(ctx).Add(1)102103go func(plg Plugin) {104defer dispatch.GetDispatchWaitGroup(ctx).Done()105106err := plg.Apply(ctx, opts)107if err == context.Canceled || err == context.DeadlineExceeded {108err = nil109}110if err != nil {111log.WithError(err).WithFields(ws.OWI()).WithField("plugin", plg.Name()).Error("cgroup plugin failure")112host.pluginActivationTotalVec.WithLabelValues(plg.Name(), "false").Inc()113} else {114host.pluginActivationTotalVec.WithLabelValues(plg.Name(), "true").Inc()115}116}(plg)117}118119return nil120}121122type Plugin interface {123Name() string124Type() Version125Apply(ctx context.Context, options *PluginOptions) error126}127128type Version int129130const (131Version1 Version = iota132Version2133)134135type PluginOptions struct {136BasePath string137CgroupPath string138InstanceId string139Annotations map[string]string140}141142143