...

Source file src/edge-infra.dev/pkg/sds/devices/k8s/apis/v1/cache.go

Documentation: edge-infra.dev/pkg/sds/devices/k8s/apis/v1

     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  // readDeviceClassFromPersistence will read and convert the device classes
    25  // specified file path to a device class list
    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  // readDeviceFromPersistence will read and convert the device classes
    51  // specified file path to a device class list
    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  // Write will write list of device classes to file system in json format
    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  	// remove annotations, labels and metadata
    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  // Write will write list of device classes to file system in json format
   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  	// remove annotations, labels and metadata
   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  // applyWriteIfDiff will only write target contents if there is
   129  // a diff between the current and target content
   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