Skip to content

Commit c322bf4

Browse files
refactor: align size policies with Kubernetes resource quantity conventions
- Updated size policies from int-based values to resource.Quantity for consistency with Kubernetes resource limits. - Enabled the use of units such as Ki, Mi, Gi for max checkpoint size and total size policies. Signed-off-by: Parthiba-Hazra <[email protected]>
1 parent c48b886 commit c322bf4

4 files changed

+117
-107
lines changed

api/v1/checkpointrestoreoperator_types.go

+23-22
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package v1
1818

1919
import (
20+
"k8s.io/apimachinery/pkg/api/resource"
2021
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2122
)
2223

@@ -34,37 +35,37 @@ type CheckpointRestoreOperatorSpec struct {
3435
}
3536

3637
type GlobalPolicySpec struct {
37-
MaxCheckpointsPerNamespaces *int `json:"maxCheckpointsPerNamespace,omitempty"`
38-
MaxCheckpointsPerPod *int `json:"maxCheckpointsPerPod,omitempty"`
39-
MaxCheckpointsPerContainer *int `json:"maxCheckpointsPerContainer,omitempty"`
40-
MaxCheckpointSize *int `json:"maxCheckpointSize,omitempty"`
41-
MaxTotalSizePerNamespace *int `json:"maxTotalSizePerNamespace,omitempty"`
42-
MaxTotalSizePerPod *int `json:"maxTotalSizePerPod,omitempty"`
43-
MaxTotalSizePerContainer *int `json:"maxTotalSizePerContainer,omitempty"`
38+
MaxCheckpointsPerNamespaces *int `json:"maxCheckpointsPerNamespace,omitempty"`
39+
MaxCheckpointsPerPod *int `json:"maxCheckpointsPerPod,omitempty"`
40+
MaxCheckpointsPerContainer *int `json:"maxCheckpointsPerContainer,omitempty"`
41+
MaxCheckpointSize *resource.Quantity `json:"maxCheckpointSize,omitempty"`
42+
MaxTotalSizePerNamespace *resource.Quantity `json:"maxTotalSizePerNamespace,omitempty"`
43+
MaxTotalSizePerPod *resource.Quantity `json:"maxTotalSizePerPod,omitempty"`
44+
MaxTotalSizePerContainer *resource.Quantity `json:"maxTotalSizePerContainer,omitempty"`
4445
}
4546

4647
type ContainerPolicySpec struct {
47-
Namespace string `json:"namespace,omitempty"`
48-
Pod string `json:"pod,omitempty"`
49-
Container string `json:"container,omitempty"`
50-
MaxCheckpoints *int `json:"maxCheckpoints,omitempty"`
51-
MaxCheckpointSize *int `json:"maxCheckpointSize,omitempty"`
52-
MaxTotalSize *int `json:"maxTotalSize,omitempty"`
48+
Namespace string `json:"namespace,omitempty"`
49+
Pod string `json:"pod,omitempty"`
50+
Container string `json:"container,omitempty"`
51+
MaxCheckpoints *int `json:"maxCheckpoints,omitempty"`
52+
MaxCheckpointSize *resource.Quantity `json:"maxCheckpointSize,omitempty"`
53+
MaxTotalSize *resource.Quantity `json:"maxTotalSize,omitempty"`
5354
}
5455

5556
type PodPolicySpec struct {
56-
Namespace string `json:"namespace,omitempty"`
57-
Pod string `json:"pod,omitempty"`
58-
MaxCheckpoints *int `json:"maxCheckpoints,omitempty"`
59-
MaxCheckpointSize *int `json:"maxCheckpointSize,omitempty"`
60-
MaxTotalSize *int `json:"maxTotalSize,omitempty"`
57+
Namespace string `json:"namespace,omitempty"`
58+
Pod string `json:"pod,omitempty"`
59+
MaxCheckpoints *int `json:"maxCheckpoints,omitempty"`
60+
MaxCheckpointSize *resource.Quantity `json:"maxCheckpointSize,omitempty"`
61+
MaxTotalSize *resource.Quantity `json:"maxTotalSize,omitempty"`
6162
}
6263

6364
type NamespacePolicySpec struct {
64-
Namespace string `json:"namespace,omitempty"`
65-
MaxCheckpoints *int `json:"maxCheckpoints,omitempty"`
66-
MaxCheckpointSize *int `json:"maxCheckpointSize,omitempty"`
67-
MaxTotalSize *int `json:"maxTotalSize,omitempty"`
65+
Namespace string `json:"namespace,omitempty"`
66+
MaxCheckpoints *int `json:"maxCheckpoints,omitempty"`
67+
MaxCheckpointSize *resource.Quantity `json:"maxCheckpointSize,omitempty"`
68+
MaxTotalSize *resource.Quantity `json:"maxTotalSize,omitempty"`
6869
}
6970

7071
// CheckpointRestoreOperatorStatus defines the observed state of CheckpointRestoreOperator

api/v1/zz_generated.deepcopy.go

+20-20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/controller/checkpointrestoreoperator_controller.go

+65-56
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
metadata "github.com/checkpoint-restore/checkpointctl/lib"
3737
"github.com/containers/storage/pkg/archive"
3838
"github.com/go-logr/logr"
39+
"k8s.io/apimachinery/pkg/api/resource"
3940
"k8s.io/apimachinery/pkg/runtime"
4041
kubelettypes "k8s.io/kubelet/pkg/types"
4142
ctrl "sigs.k8s.io/controller-runtime"
@@ -54,24 +55,18 @@ const (
5455
BySize
5556
)
5657

57-
// Constants for unit conversion
58-
const (
59-
KB = 1024
60-
MB = 1024 * KB
61-
)
62-
6358
var (
6459
GarbageCollector garbageCollector
6560
policyMutex sync.RWMutex
6661
checkpointDirectory string = "/var/lib/kubelet/checkpoints"
6762
quit chan bool
68-
maxCheckpointsPerContainer int = 10
69-
maxCheckpointsPerPod int = 20
70-
maxCheckpointsPerNamespace int = 30
71-
maxCheckpointSize int = math.MaxInt32
72-
maxTotalSizePerPod int = math.MaxInt32
73-
maxTotalSizePerContainer int = math.MaxInt32
74-
maxTotalSizePerNamespace int = math.MaxInt32
63+
maxCheckpointsPerContainer int = 10
64+
maxCheckpointsPerPod int = 20
65+
maxCheckpointsPerNamespace int = 30
66+
maxCheckpointSize resource.Quantity = resource.MustParse("1Ei")
67+
maxTotalSizePerPod resource.Quantity = resource.MustParse("1Ei")
68+
maxTotalSizePerContainer resource.Quantity = resource.MustParse("1Ei")
69+
maxTotalSizePerNamespace resource.Quantity = resource.MustParse("1Ei")
7570
containerPolicies []criuorgv1.ContainerPolicySpec
7671
podPolicies []criuorgv1.PodPolicySpec
7772
namespacePolicies []criuorgv1.NamespacePolicySpec
@@ -124,10 +119,10 @@ func resetAllPoliciesToDefault(log logr.Logger) {
124119
maxCheckpointsPerContainer = 10
125120
maxCheckpointsPerPod = 20
126121
maxCheckpointsPerNamespace = 30
127-
maxCheckpointSize = math.MaxInt32
128-
maxTotalSizePerContainer = math.MaxInt32
129-
maxTotalSizePerPod = math.MaxInt32
130-
maxTotalSizePerNamespace = math.MaxInt32
122+
maxCheckpointSize = resource.MustParse("1Ei")
123+
maxTotalSizePerContainer = resource.MustParse("1Ei")
124+
maxTotalSizePerPod = resource.MustParse("1Ei")
125+
maxTotalSizePerNamespace = resource.MustParse("1Ei")
131126

132127
containerPolicies = nil
133128
podPolicies = nil
@@ -155,24 +150,24 @@ func (r *CheckpointRestoreOperatorReconciler) handleGlobalPolicies(log logr.Logg
155150
log.Info("Changed MaxCheckpointsPerNamespace", "maxCheckpointsPerNamespace", maxCheckpointsPerNamespace)
156151
}
157152

158-
if globalPolicies.MaxCheckpointSize != nil && *globalPolicies.MaxCheckpointSize >= 0 {
159-
maxCheckpointSize = *globalPolicies.MaxCheckpointSize * MB
160-
log.Info("Changed MaxCheckpointSize", "maxCheckpointSize", maxCheckpointSize)
153+
if globalPolicies.MaxCheckpointSize != nil {
154+
maxCheckpointSize = *globalPolicies.MaxCheckpointSize
155+
log.Info("Changed MaxCheckpointSize", "maxCheckpointSize", maxCheckpointSize.String())
161156
}
162157

163-
if globalPolicies.MaxTotalSizePerNamespace != nil && *globalPolicies.MaxTotalSizePerNamespace >= 0 {
164-
maxTotalSizePerNamespace = *globalPolicies.MaxTotalSizePerNamespace * MB
165-
log.Info("Changed MaxTotalSizePerNamespace", "maxTotalSizePerNamespace", maxTotalSizePerNamespace)
158+
if globalPolicies.MaxTotalSizePerNamespace != nil {
159+
maxTotalSizePerNamespace = *globalPolicies.MaxTotalSizePerNamespace
160+
log.Info("Changed MaxTotalSizePerNamespace", "maxTotalSizePerNamespace", maxTotalSizePerNamespace.String())
166161
}
167162

168-
if globalPolicies.MaxTotalSizePerPod != nil && *globalPolicies.MaxTotalSizePerPod >= 0 {
169-
maxTotalSizePerPod = *globalPolicies.MaxTotalSizePerPod * MB
170-
log.Info("Changed MaxTotalSizePerPod", "maxTotalSizePerPod", maxTotalSizePerPod)
163+
if globalPolicies.MaxTotalSizePerPod != nil {
164+
maxTotalSizePerPod = *globalPolicies.MaxTotalSizePerPod
165+
log.Info("Changed MaxTotalSizePerPod", "maxTotalSizePerPod", maxTotalSizePerPod.String())
171166
}
172167

173-
if globalPolicies.MaxTotalSizePerContainer != nil && *globalPolicies.MaxTotalSizePerContainer >= 0 {
174-
maxTotalSizePerContainer = *globalPolicies.MaxTotalSizePerContainer * MB
175-
log.Info("Changed MaxTotalSizePerContainer", "maxTotalSizePerContainer", maxTotalSizePerContainer)
168+
if globalPolicies.MaxTotalSizePerContainer != nil {
169+
maxTotalSizePerContainer = *globalPolicies.MaxTotalSizePerContainer
170+
log.Info("Changed MaxTotalSizePerContainer", "maxTotalSizePerContainer", maxTotalSizePerContainer.String())
176171
}
177172
}
178173

@@ -332,38 +327,47 @@ func getCheckpointArchiveInformation(log logr.Logger, checkpointPath string) (*c
332327

333328
type Policy struct {
334329
MaxCheckpoints int
335-
MaxCheckpointSize int
336-
MaxTotalSize int
330+
MaxCheckpointSize resource.Quantity
331+
MaxTotalSize resource.Quantity
337332
}
338333

339334
func applyPolicies(log logr.Logger, details *checkpointDetails) {
340335
policyMutex.Lock()
341336
defer policyMutex.Unlock()
342337

343-
toInfinity := func(value *int) int {
338+
// Function to handle default "infinity" value for count-based policies
339+
toInfinityCount := func(value *int) int {
344340
if value == nil {
345341
return math.MaxInt32
346342
}
347343
return *value
348344
}
349345

346+
// Function to handle default "infinity" value for size-based policies
347+
toInfinitySize := func(value *resource.Quantity) resource.Quantity {
348+
if value == nil {
349+
return resource.MustParse("1Ei")
350+
}
351+
return *value
352+
}
353+
350354
if policy := findContainerPolicy(details); policy != nil {
351355
handleCheckpointsForLevel(log, details, "container", Policy{
352-
MaxCheckpoints: toInfinity(policy.MaxCheckpoints),
353-
MaxCheckpointSize: toInfinity(policy.MaxCheckpointSize) * MB,
354-
MaxTotalSize: toInfinity(policy.MaxTotalSize) * MB,
356+
MaxCheckpoints: toInfinityCount(policy.MaxCheckpoints),
357+
MaxCheckpointSize: toInfinitySize(policy.MaxCheckpointSize),
358+
MaxTotalSize: toInfinitySize(policy.MaxTotalSize),
355359
})
356360
} else if policy := findPodPolicy(details); policy != nil {
357361
handleCheckpointsForLevel(log, details, "pod", Policy{
358-
MaxCheckpoints: toInfinity(policy.MaxCheckpoints),
359-
MaxCheckpointSize: toInfinity(policy.MaxCheckpointSize) * MB,
360-
MaxTotalSize: toInfinity(policy.MaxTotalSize) * MB,
362+
MaxCheckpoints: toInfinityCount(policy.MaxCheckpoints),
363+
MaxCheckpointSize: toInfinitySize(policy.MaxCheckpointSize),
364+
MaxTotalSize: toInfinitySize(policy.MaxTotalSize),
361365
})
362366
} else if policy := findNamespacePolicy(details); policy != nil {
363367
handleCheckpointsForLevel(log, details, "namespace", Policy{
364-
MaxCheckpoints: toInfinity(policy.MaxCheckpoints),
365-
MaxCheckpointSize: toInfinity(policy.MaxCheckpointSize) * MB,
366-
MaxTotalSize: toInfinity(policy.MaxTotalSize) * MB,
368+
MaxCheckpoints: toInfinityCount(policy.MaxCheckpoints),
369+
MaxCheckpointSize: toInfinitySize(policy.MaxCheckpointSize),
370+
MaxTotalSize: toInfinitySize(policy.MaxTotalSize),
367371
})
368372
} else {
369373
// Apply global policies if no specific policy found
@@ -466,11 +470,11 @@ func handleCheckpointsForLevel(log logr.Logger, details *checkpointDetails, leve
466470
log.Info("MaxCheckpoints is less than or equal to 0, skipping checkpoint handling", "level", level, "policy.MaxCheckpoints", policy.MaxCheckpoints)
467471
return
468472
}
469-
if policy.MaxCheckpointSize <= 0 {
473+
if policy.MaxCheckpointSize.Value() <= 0 {
470474
log.Info("MaxCheckpointSize is less than or equal to 0, skipping checkpoint handling", "level", level, "policy.MaxCheckpointSize", policy.MaxCheckpointSize)
471475
return
472476
}
473-
if policy.MaxTotalSize <= 0 {
477+
if policy.MaxTotalSize.Value() <= 0 {
474478
log.Info("MaxTotalSize is less than or equal to 0, skipping checkpoint handling", "level", level, "policy.MaxTotalSize", policy.MaxTotalSize)
475479
return
476480
}
@@ -529,7 +533,7 @@ func handleCheckpointsForLevel(log logr.Logger, details *checkpointDetails, leve
529533
}
530534

531535
checkpointArchivesCounter := len(filteredArchives)
532-
totalSize := int64(0)
536+
totalSize := resource.NewQuantity(0, resource.BinarySI)
533537
archiveSizes := make(map[string]int64)
534538
archivesToDelete := make(map[int64]string)
535539

@@ -540,16 +544,19 @@ func handleCheckpointsForLevel(log logr.Logger, details *checkpointDetails, leve
540544
continue
541545
}
542546

543-
log.Info("Checkpoint archive details", "archive", c, "size", fi.Size(), "maxCheckpointSize", policy.MaxCheckpointSize)
544-
if policy.MaxCheckpointSize > 0 && fi.Size() > int64(policy.MaxCheckpointSize) {
545-
log.Info("Deleting checkpoint archive due to exceeding MaxCheckpointSize", "archive", c, "size", fi.Size(), "maxCheckpointSize", policy.MaxCheckpointSize)
547+
currentSize := resource.NewQuantity(fi.Size(), resource.BinarySI)
548+
log.Info("Checkpoint archive details", "archive", c, "size", currentSize.String(), "maxCheckpointSize", policy.MaxCheckpointSize.String())
549+
550+
if policy.MaxCheckpointSize.Cmp(*currentSize) < 0 {
551+
log.Info("Deleting checkpoint archive due to exceeding MaxCheckpointSize", "archive", c, "size", currentSize.String(), "maxCheckpointSize", policy.MaxCheckpointSize.String())
546552
err := os.Remove(c)
547553
if err != nil {
548554
log.Error(err, "failed to remove checkpoint archive", "archive", c)
549555
}
550556
continue
551557
}
552-
totalSize += fi.Size()
558+
559+
totalSize.Add(*currentSize)
553560
archiveSizes[c] = fi.Size()
554561
archivesToDelete[fi.ModTime().UnixMicro()] = c
555562
}
@@ -558,7 +565,7 @@ func handleCheckpointsForLevel(log logr.Logger, details *checkpointDetails, leve
558565
if policy.MaxCheckpoints > 0 && checkpointArchivesCounter > policy.MaxCheckpoints {
559566
excessCount := int64(checkpointArchivesCounter - policy.MaxCheckpoints)
560567
log.Info("Checkpoint count exceeds limit", "checkpointArchivesCounter", checkpointArchivesCounter, "maxCheckpoints", policy.MaxCheckpoints, "excessCount", excessCount)
561-
toDelete := selectArchivesToDelete(log, checkpointArchives, archiveSizes, excessCount, ByCount)
568+
toDelete := selectArchivesToDelete(log, filteredArchives, archiveSizes, excessCount, ByCount)
562569
for _, archive := range toDelete {
563570
log.Info("Deleting checkpoint archive due to excess count", "archive", archive)
564571
err := os.Remove(archive)
@@ -573,19 +580,21 @@ func handleCheckpointsForLevel(log logr.Logger, details *checkpointDetails, leve
573580
}
574581

575582
// Handle total size against maxTotalSize
576-
if policy.MaxTotalSize > 0 && totalSize > int64(policy.MaxTotalSize) {
577-
excessSize := totalSize - int64(policy.MaxTotalSize)
578-
log.Info("Total size of checkpoint archives exceeds limit", "totalSize", totalSize, "maxTotalSize", policy.MaxTotalSize, "excessSize", excessSize)
579-
toDelete := selectArchivesToDelete(log, filteredArchives, archiveSizes, excessSize, BySize)
583+
if policy.MaxTotalSize.Cmp(*totalSize) < 0 {
584+
excessSize := totalSize.DeepCopy()
585+
excessSize.Sub(policy.MaxTotalSize)
586+
log.Info("Total size of checkpoint archives exceeds limit", "totalSize", totalSize.String(), "maxTotalSize", policy.MaxTotalSize.String(), "excessSize", excessSize.String())
587+
toDelete := selectArchivesToDelete(log, filteredArchives, archiveSizes, excessSize.Value(), BySize)
580588
for _, archive := range toDelete {
581589
log.Info("Deleting checkpoint archive due to excess size", "archive", archive)
582590
err := os.Remove(archive)
583591
if err != nil {
584-
log.Error(err, "Removal of checkpoint archive failed", "archive", archive)
592+
log.Error(err, "removal of checkpoint archive failed", "archive", archive)
585593
}
586-
totalSize -= archiveSizes[archive]
594+
currentSize := resource.NewQuantity(archiveSizes[archive], resource.BinarySI)
595+
totalSize.Sub(*currentSize)
587596
delete(archiveSizes, archive)
588-
if totalSize <= int64(policy.MaxTotalSize) {
597+
if policy.MaxTotalSize.Cmp(*totalSize) >= 0 {
589598
break
590599
}
591600
}

0 commit comments

Comments
 (0)