quota

package
v0.0.0-...-554ba31 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 18, 2024 License: GPL-3.0 Imports: 12 Imported by: 51

Documentation

Overview

Package quota defines state structures for resource quota groups for snaps.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ResolveCrossReferences

func ResolveCrossReferences(grps map[string]*Group) error

ResolveCrossReferences takes a set of deserialized groups and sets all cross references amongst them using the unexported fields which are not serialized.

Types

type Group

type Group struct {
	// Name is the name of the quota group. This name is used the
	// name of the systemd slice underlying the quota group.
	// Certain names are reserved for future use: system, snapd, root, user.
	// Otherwise names following the same rules as snap names can be used.
	Name string `json:"name,omitempty"`

	// SubGroups is the set of sub-groups that are subject to this quota.
	// Sub-groups have their own limits, subject to the requirement that the
	// highest quota for a sub-group is that of the parent group.
	SubGroups []string `json:"sub-groups,omitempty"`

	// MemoryLimit is the limit of memory available to the processes in the
	// group where if the total used memory of all the processes exceeds the
	// limit, oom-killer is invoked which will start killing processes. The
	// specific behavior of which processes are killed is subject to the
	// ExhaustionBehavior. MemoryLimit is expressed in bytes.
	MemoryLimit quantity.Size `json:"memory-limit,omitempty"`

	// CPULimit is the quotas for the cpu and consists of a couple of nubs.
	// It is possible to control the percentage of the cpu available for the group
	// and which cores (requires cgroupsv2) are allowed to be used.
	CPULimit *GroupQuotaCPU `json:"cpu-limit,omitempty"`

	// ThreadLimit is the limit of threads/processes that can be active at once in
	// the group. Once the limit is reached, further forks() or clones() will be blocked
	// for processes in the group.
	ThreadLimit int `json:"task-limit,omitempty"`

	// JournalLimit is the limits that apply to the journal for this quota group. When
	// this limit is present, then the quota group will be assigned a log namespace for
	// journald.
	JournalLimit *GroupQuotaJournal `json:"journal-limit,omitempty"`

	// ParentGroup is the the parent group that this group is a child of. If it
	// is empty, then this is a "root" quota group.
	ParentGroup string `json:"parent-group,omitempty"`

	// Snaps is the set of snaps that is part of this quota group. If both this
	// and Services is empty then the underlying slice may not exist on the system.
	Snaps []string `json:"snaps,omitempty"`

	// Services is the set of snap services that is part of this quota group. The entries here
	// are in the format of snap-name.service-name, and the snap-name will refer to a snap in a
	// parent quota group. If both this and Snaps is empty then the underlying slice may not
	// exist on the system.
	Services []string `json:"services,omitempty"`
	// contains filtered or unexported fields
}

Group is a quota group of snaps, services or sub-groups that are all subject to specific resource quotas. The only quota resource types currently supported is memory, but this can be expanded in the future.

func NewGroup

func NewGroup(name string, resourceLimits Resources) (*Group, error)

NewGroup creates a new top quota group with the given name and memory limit.

func (*Group) CurrentMemoryUsage

func (grp *Group) CurrentMemoryUsage() (quantity.Size, error)

CurrentMemoryUsage returns the current memory usage of the quota group. For quota groups which do not yet have a backing systemd slice on the system ( i.e. quota groups without any snaps in them), the memory usage is reported as 0.

func (*Group) CurrentTaskUsage

func (grp *Group) CurrentTaskUsage() (int, error)

CurrentTaskUsage returns the current task (processes, threads) usage of the quota group. For quota groups which do not yet have a backing systemd slice on the system ( i.e. quota groups without any snaps in them), the task usage is reported as 0

func (*Group) GetCPUSetQuota

func (grp *Group) GetCPUSetQuota() []int

GetCPUSetQuota returns the currently active CPU set quota for this group, which includes the case where the CPU set is inherited from a parent group.

func (*Group) GetLocalCPUQuota

func (grp *Group) GetLocalCPUQuota() (int, int)

GetLocalCPUQuota returns the final calculated count and percentage of the current CPU quota for the group. This does not return any inherited CPU quota, but it does take any inherited CPU set into account to adjust in the case of a relative usage percentage. If the CPU count is set to 0, then it is expected that it returns CPULimit.Percentage times the number of all allowed cores. This is either the full amount of cores present on the system, or it is the number of cores allowed for this group. Otherwise this command should return the actual count and percentage set by the group.

func (*Group) GetLocalCPUSetQuota

func (grp *Group) GetLocalCPUSetQuota() []int

GetLocalCPUSetQuota returns the current CPU set quota for the group. This does not return any inheritted CPU set quota.

func (*Group) GetQuotaResources

func (grp *Group) GetQuotaResources() Resources

func (*Group) JournalConfFileName

func (grp *Group) JournalConfFileName() string

JournalConfFileName returns the name of the journal configuration file that should be used for this quota group. As an example, a group named "foo" will return a name of journald@snap-foo.conf

func (*Group) JournalNamespaceName

func (grp *Group) JournalNamespaceName() string

JournalNamespaceName returns the snap formatted name of the log namespace, corresponding to the namespace of the journal quota affecting this group. If this group is a service group, this returns the journal namespace name for the parent group instead.

func (*Group) JournalQuotaSet

func (grp *Group) JournalQuotaSet() bool

JournalQuotaSet returns true if the group is subject to a journal quota. This should only be used in cases where the caller is interested in knowing if a quota group is affected by a journal quota, and not in the case where the caller needs to know if the group itself has a journal quota set. For service groups this depends on their parent quota group.

func (*Group) JournalServiceDropInDir

func (grp *Group) JournalServiceDropInDir() string

JournalServiceFile returns the directory specific to this quota group for its journal service unit drop-in.

func (*Group) JournalServiceDropInFile

func (grp *Group) JournalServiceDropInFile() string

JournalServiceDropInFile returns the full path to the journal service unit drop-in file for the quota group.

func (*Group) JournalServiceName

func (grp *Group) JournalServiceName() string

JournalServiceName returns the systemd service name for the quota group.

func (*Group) NewSubGroup

func (grp *Group) NewSubGroup(name string, resourceLimits Resources) (*Group, error)

NewSubGroup creates a new sub group under the current group.

func (*Group) ServiceMap

func (grp *Group) ServiceMap() map[string]*Group

ServiceMap calculates a map of services to quota groups. If a group contains service sub-groups, this will map each service in those sub-groups to their sub-groups. If a root group contains a snap foo and service subgroup bar, with service svc1 in bar, then this will return a map with entry foo.svc1=bar

func (*Group) SliceFileName

func (grp *Group) SliceFileName() string

SliceFileName returns the name of the slice file that should be used for this quota group. This name will include all of the group's parents in the name. For example, a group named "bar" that is a child of the "foo" group will have a systemd slice name as "snap.foo-bar.slice". Note that the slice name may differ from the snapd friendly group name, mainly in the case that the group is a sub group.

func (*Group) UpdateQuotaLimits

func (grp *Group) UpdateQuotaLimits(resourceLimits Resources) error

UpdateQuotaLimits updates all the quota limits set for the group to the new limits given. The limits will be validated against the group's parent group's limits, to verify that they fit. For instance, if the parent group has a memory limit of 1GB, and the new limit given here is 2GB, then the new limit will be rejected.

func (*Group) ValidateNestingAndSnaps

func (grp *Group) ValidateNestingAndSnaps() error

ValidateNestingAndSnaps takes a group and verifies that it satisfies the following conditions:

  1. That if any parent is mixed (has both snaps and sub-groups), it must be the immediate parent group.
  2. If the group itself is mixed, that it has only one level of sub-grouping.

type GroupQuotaCPU

type GroupQuotaCPU struct {
	// Count is the multiplier that is used in combination with the
	// percentage parameter to determine the final CPU resource constraint value.
	// The value is a positive integer or 0. A value of 0 will be treated as 1.
	Count int `json:"count,omitempty"`

	// Percentage is a positive integer between 0 and 100. It is used to together with
	// the Count parameter to determine the final CPU resource constraint value. The value
	// written to the systemd slice will be Count*Percentage. A value of 0 means that the limit
	// in Percentage and Count is ignored.
	Percentage int `json:"percentage,omitempty"`

	// CPUSet is a list of CPU core indices that are allowed to be used by the group. Each value
	// in the list refers to the CPU core number. If the list is empty, all CPU cores are allowed.
	CPUSet []int `json:"allowed-cpus,omitempty"`
}

GroupQuotaCPU contains the different knobs that can be tuned for cpu quota limits. The allowed CPU percentage to use is split across two limits to better support a inituitive way of setting the limits.

type GroupQuotaJournal

type GroupQuotaJournal struct {
	// Size is the maximum allowed size of the journal for the group.
	// If the size is set below current usage, systemd will automatically treat
	// the current usage of the journald namespace as the minimum limit and
	// render whatever set here ineffective. The maximum allowed size for
	// journald namespaces is 4GB. A value of 0 here means no limit is present.
	Size quantity.Size `json:"size,omitempty"`

	// RateEnabled tells us whether or not the values provided in RateCount and
	// RatePeriod should be written.
	RateEnabled bool `json:"rate-enabled,omitempty"`
	// RateCount is the number of messages allowed each RatePeriod. A zero value
	// in this field will disable the rate-limit.
	RateCount int `json:"rate-count,omitempty"`
	// RatePeriod is the time-period for when the rate resets. Each RatePeriod,
	// RateCount number of messages is allowed. A zero value in this field will
	// disable the rate-limit.
	RatePeriod time.Duration `json:"rate-period,omitempty"`
}

GroupQuotaJournal contains the supported limits for journald. Any limit set here applies only to the quota group itself. Journal limits will not be inherited by the sub-groups as this behaviour is not supported by systemd.

type QuotaGroupSet

type QuotaGroupSet struct {
	// contains filtered or unexported fields
}

QuotaGroupSet is a set of quota groups, it is used for tracking a set of necessary quota groups using AddAllNecessaryGroups to add groups (and their implicit dependencies), and AllQuotaGroups to enumerate all the quota groups in the set.

func (*QuotaGroupSet) AddAllNecessaryGroups

func (s *QuotaGroupSet) AddAllNecessaryGroups(grp *Group) error

AddAllNecessaryGroups adds all groups that are required for the specified group to be effective to the set. This means all sub-groups of this group, all parent groups of this group, and all sub-trees of any parent groups. This set is the set of quota groups that must exist for this quota group to be fully realized on a system, since all sub-branches of the full tree must exist since this group may share some quota resources with the other branches. There is no support for manipulating group trees while accumulating to a QuotaGroupSet using this.

func (*QuotaGroupSet) AllQuotaGroups

func (s *QuotaGroupSet) AllQuotaGroups() []*Group

AllQuotaGroups returns a flattend list of all quota groups and necessary quota groups that have been added to the set.

type ResourceCPU

type ResourceCPU struct {
	Count      int `json:"count"`
	Percentage int `json:"percentage"`
}

type ResourceCPUSet

type ResourceCPUSet struct {
	CPUs []int `json:"cpus"`
}

type ResourceJournal

type ResourceJournal struct {
	Size *ResourceJournalSize `json:"size,omitempty"`
	Rate *ResourceJournalRate `json:"rate,omitempty"`
}

ResourceJournal represents the available journal quotas. It's structured a bit different compared to the other resources to support namespace only cases, where the existence of != nil ResourceJournal with empty values indicates that the namespace only is wanted.

type ResourceJournalRate

type ResourceJournalRate struct {
	// Count is the maximum number of journald messages per Period.
	Count  int           `json:"count"`
	Period time.Duration `json:"period"`
}

type ResourceJournalSize

type ResourceJournalSize struct {
	Limit quantity.Size `json:"limit"`
}

type ResourceMemory

type ResourceMemory struct {
	Limit quantity.Size `json:"limit"`
}

type ResourceThreads

type ResourceThreads struct {
	Limit int `json:"limit"`
}

type Resources

type Resources struct {
	Memory  *ResourceMemory  `json:"memory,omitempty"`
	CPU     *ResourceCPU     `json:"cpu,omitempty"`
	CPUSet  *ResourceCPUSet  `json:"cpu-set,omitempty"`
	Threads *ResourceThreads `json:"thread,omitempty"`
	Journal *ResourceJournal `json:"journal,omitempty"`
}

Resources are built up of multiple quota limits. Each quota limit is a pointer value to indicate that their presence may be optional, and because we want to detect whenever someone changes a limit to '0' explicitly.

func (*Resources) Change

func (qr *Resources) Change(newLimits Resources) error

Change updates the current quota limits with the new limits. Additional verification logic exists for this operation compared to when setting initial limits. Some changes of limits are not allowed.

func (*Resources) CheckFeatureRequirements

func (qr *Resources) CheckFeatureRequirements() error

CheckFeatureRequirements checks if the current system meets the requirements for the given resource request.

E.g. a CPUSet only only be set set on systems with cgroup v2.

func (*Resources) Unset

func (qr *Resources) Unset() bool

Unset returns true if there is no limit set

func (*Resources) Validate

func (qr *Resources) Validate() error

Validate performs basic validation of the provided quota resources for a group. The restrictions imposed are that at least one limit should be set, and each of the imposed limits are not zero.

Note that before applying the quota to the system CheckFeatureRequirements() should be called.

func (*Resources) ValidateChange

func (qr *Resources) ValidateChange(newLimits Resources) error

ValidateChange performs validation of new quota limits against the current limits. We do this validation each time a new group/subgroup is created or updated. This is to catch issues where we want to guard against lowering limits where not supported or to make sure that certain/all limits are not removed. We also require memory limits are above 640kB.

type ResourcesBuilder

type ResourcesBuilder struct {
	MemoryLimit    quantity.Size
	MemoryLimitSet bool

	CPUCount    int
	CPUCountSet bool

	CPUPercentage    int
	CPUPercentageSet bool

	CPUSet    []int
	CPUSetSet bool

	ThreadLimit    int
	ThreadLimitSet bool

	JournalNamespaceSet bool

	JournalSizeLimit    quantity.Size
	JournalSizeLimitSet bool

	JournalRateCountLimit  int
	JournalRatePeriodLimit time.Duration
	JournalRateSet         bool
}

func NewResourcesBuilder

func NewResourcesBuilder() *ResourcesBuilder

func (*ResourcesBuilder) Build

func (rb *ResourcesBuilder) Build() Resources

func (*ResourcesBuilder) WithCPUCount

func (rb *ResourcesBuilder) WithCPUCount(count int) *ResourcesBuilder

func (*ResourcesBuilder) WithCPUPercentage

func (rb *ResourcesBuilder) WithCPUPercentage(percentage int) *ResourcesBuilder

func (*ResourcesBuilder) WithCPUSet

func (rb *ResourcesBuilder) WithCPUSet(cpuSet []int) *ResourcesBuilder

func (*ResourcesBuilder) WithJournalNamespace

func (rb *ResourcesBuilder) WithJournalNamespace() *ResourcesBuilder

func (*ResourcesBuilder) WithJournalRate

func (rb *ResourcesBuilder) WithJournalRate(count int, period time.Duration) *ResourcesBuilder

func (*ResourcesBuilder) WithJournalSize

func (rb *ResourcesBuilder) WithJournalSize(limit quantity.Size) *ResourcesBuilder

func (*ResourcesBuilder) WithMemoryLimit

func (rb *ResourcesBuilder) WithMemoryLimit(limit quantity.Size) *ResourcesBuilder

func (*ResourcesBuilder) WithThreadLimit

func (rb *ResourcesBuilder) WithThreadLimit(limit int) *ResourcesBuilder

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL