1 package v1
2
3 import (
4 "context"
5 "encoding/json"
6 "errors"
7 "fmt"
8 "os"
9 "path/filepath"
10
11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12
13 "edge-infra.dev/pkg/lib/filesystem"
14 "edge-infra.dev/pkg/sds/devices/logger"
15 )
16
17 const (
18 deviceClassCacheName = "deviceclasses.json"
19 deviceCacheName = "devicesets.json"
20 deviceRuleCacheName = "devicerules.json"
21 deviceFilePerms os.FileMode = 0600
22 )
23
24
25
26 func readDeviceClassFromPersistence(path string) (map[string]*DeviceClass, error) {
27 path = filepath.Join(path, deviceClassCacheName)
28
29 if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
30 return map[string]*DeviceClass{}, nil
31 }
32 jsonDoc, err := os.ReadFile(path)
33 if err != nil {
34 return map[string]*DeviceClass{}, err
35 }
36
37 deviceClasses := DeviceClassList{}
38 if err := json.Unmarshal(jsonDoc, &deviceClasses); err != nil {
39 return map[string]*DeviceClass{}, fmt.Errorf("failed to unmarshal to json: %v", err)
40 }
41
42 deviceClassMap := map[string]*DeviceClass{}
43 for _, class := range deviceClasses.Items {
44 newClass := &class
45 deviceClassMap[class.ClassName()] = newClass
46 }
47 return deviceClassMap, nil
48 }
49
50
51
52 func readDeviceFromPersistence(path string) ([]*DeviceSet, error) {
53 path = filepath.Join(path, deviceCacheName)
54
55 if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
56 return []*DeviceSet{}, nil
57 }
58 jsonDoc, err := os.ReadFile(path)
59 if err != nil {
60 return []*DeviceSet{}, err
61 }
62
63 deviceList := DeviceSetList{}
64 if err := json.Unmarshal(jsonDoc, &deviceList); err != nil {
65 return []*DeviceSet{}, fmt.Errorf("failed to unmarshal to json: %v", err)
66 }
67
68 devices := []*DeviceSet{}
69 for _, device := range deviceList.Items {
70 newDevice := &device
71 devices = append(devices, newDevice)
72 }
73 return devices, nil
74 }
75
76
77 func writeDeviceClassCache(ctx context.Context, path string, deviceClasses []DeviceClass) error {
78 log := logger.FromContext(ctx)
79 classNames := []string{}
80
81 path = filepath.Join(path, deviceClassCacheName)
82
83
84 for idx, class := range deviceClasses {
85 metadata := metav1.ObjectMeta{
86 Name: class.ObjectMeta.GetName(),
87 Generation: class.ObjectMeta.Generation,
88 }
89 class.ObjectMeta = metadata
90 deviceClasses[idx] = class
91 classNames = append(classNames, class.ClassName())
92 }
93
94 log.Debug("caching device classes", "classes", classNames)
95 target, err := json.Marshal(DeviceClassList{Items: deviceClasses})
96 if err != nil {
97 return fmt.Errorf("failed to marshal to json: %v", err)
98 }
99 return applyWriteIfDiff(target, path)
100 }
101
102
103 func writeDevicesCache(ctx context.Context, path string, devices []DeviceSet) error {
104 log := logger.FromContext(ctx)
105 names := []string{}
106
107 path = filepath.Join(path, deviceCacheName)
108
109
110 for idx, dev := range devices {
111 metadata := metav1.ObjectMeta{
112 Name: dev.ObjectMeta.GetName(),
113 Generation: dev.ObjectMeta.Generation,
114 }
115 dev.ObjectMeta = metadata
116 devices[idx] = dev
117 names = append(names, dev.Name())
118 }
119
120 log.Debug("caching devices", "devices", names)
121 target, err := json.Marshal(DeviceSetList{Items: devices})
122 if err != nil {
123 return fmt.Errorf("failed to marshal to json: %v", err)
124 }
125 return applyWriteIfDiff(target, path)
126 }
127
128
129
130 func applyWriteIfDiff(target []byte, path string) error {
131 isEqual, err := filesystem.FileEqualsTarget(path, target)
132 if errors.Is(err, os.ErrNotExist) || isEqual {
133 return os.WriteFile(path, target, deviceFilePerms)
134 }
135 return nil
136 }
137
View as plain text