github.com/k8snetworkplumbingwg/sriov-network-operator@v1.2.1-0.20240408194816-2d2e5a45d453/pkg/host/store/store.go (about) 1 package store 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "path/filepath" 8 9 "sigs.k8s.io/controller-runtime/pkg/log" 10 11 sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1" 12 "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts" 13 "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils" 14 "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars" 15 ) 16 17 // Contains all the file storing on the host 18 // 19 //go:generate ../../../bin/mockgen -destination mock/mock_store.go -source store.go 20 type ManagerInterface interface { 21 ClearPCIAddressFolder() error 22 SaveLastPfAppliedStatus(PfInfo *sriovnetworkv1.Interface) error 23 LoadPfsStatus(pciAddress string) (*sriovnetworkv1.Interface, bool, error) 24 25 GetCheckPointNodeState() (*sriovnetworkv1.SriovNetworkNodeState, error) 26 WriteCheckpointFile(*sriovnetworkv1.SriovNetworkNodeState) error 27 } 28 29 type manager struct{} 30 31 // NewManager: create the initial folders needed to store the info about the PF 32 // and return a manager struct that implements the ManagerInterface interface 33 func NewManager() (ManagerInterface, error) { 34 if err := createOperatorConfigFolderIfNeeded(); err != nil { 35 return nil, err 36 } 37 38 return &manager{}, nil 39 } 40 41 // createOperatorConfigFolderIfNeeded: create the operator base folder on the host 42 // together with the pci folder to save the PF status objects as json files 43 func createOperatorConfigFolderIfNeeded() error { 44 hostExtension := utils.GetHostExtension() 45 SriovConfBasePathUse := filepath.Join(hostExtension, consts.SriovConfBasePath) 46 _, err := os.Stat(SriovConfBasePathUse) 47 if err != nil { 48 if os.IsNotExist(err) { 49 err = os.MkdirAll(SriovConfBasePathUse, os.ModeDir) 50 if err != nil { 51 return fmt.Errorf("failed to create the sriov config folder on host in path %s: %v", SriovConfBasePathUse, err) 52 } 53 } else { 54 return fmt.Errorf("failed to check if the sriov config folder on host in path %s exist: %v", SriovConfBasePathUse, err) 55 } 56 } 57 58 PfAppliedConfigUse := filepath.Join(hostExtension, consts.PfAppliedConfig) 59 _, err = os.Stat(PfAppliedConfigUse) 60 if err != nil { 61 if os.IsNotExist(err) { 62 err = os.MkdirAll(PfAppliedConfigUse, os.ModeDir) 63 if err != nil { 64 return fmt.Errorf("failed to create the pci folder on host in path %s: %v", PfAppliedConfigUse, err) 65 } 66 } else { 67 return fmt.Errorf("failed to check if the pci folder on host in path %s exist: %v", PfAppliedConfigUse, err) 68 } 69 } 70 71 return nil 72 } 73 74 // ClearPCIAddressFolder: removes all the PFs storage information 75 func (s *manager) ClearPCIAddressFolder() error { 76 hostExtension := utils.GetHostExtension() 77 PfAppliedConfigUse := filepath.Join(hostExtension, consts.PfAppliedConfig) 78 _, err := os.Stat(PfAppliedConfigUse) 79 if err != nil { 80 if os.IsNotExist(err) { 81 return nil 82 } 83 return fmt.Errorf("failed to check the pci address folder path %s: %v", PfAppliedConfigUse, err) 84 } 85 86 err = os.RemoveAll(PfAppliedConfigUse) 87 if err != nil { 88 return fmt.Errorf("failed to remove the PCI address folder on path %s: %v", PfAppliedConfigUse, err) 89 } 90 91 err = os.Mkdir(PfAppliedConfigUse, os.ModeDir) 92 if err != nil { 93 return fmt.Errorf("failed to create the pci folder on host in path %s: %v", PfAppliedConfigUse, err) 94 } 95 96 return nil 97 } 98 99 // SaveLastPfAppliedStatus will save the PF object as a json into the /etc/sriov-operator/pci/<pci-address> 100 // this function must be called after running the chroot function 101 func (s *manager) SaveLastPfAppliedStatus(PfInfo *sriovnetworkv1.Interface) error { 102 data, err := json.Marshal(PfInfo) 103 if err != nil { 104 log.Log.Error(err, "failed to marshal PF status", "status", *PfInfo) 105 return err 106 } 107 108 hostExtension := utils.GetHostExtension() 109 pathFile := filepath.Join(hostExtension, consts.PfAppliedConfig, PfInfo.PciAddress) 110 err = os.WriteFile(pathFile, data, 0644) 111 return err 112 } 113 114 // LoadPfsStatus convert the /etc/sriov-operator/pci/<pci-address> json to pfstatus 115 // returns false if the file doesn't exist. 116 func (s *manager) LoadPfsStatus(pciAddress string) (*sriovnetworkv1.Interface, bool, error) { 117 hostExtension := utils.GetHostExtension() 118 pathFile := filepath.Join(hostExtension, consts.PfAppliedConfig, pciAddress) 119 pfStatus := &sriovnetworkv1.Interface{} 120 data, err := os.ReadFile(pathFile) 121 if err != nil { 122 if os.IsNotExist(err) { 123 return nil, false, nil 124 } 125 log.Log.Error(err, "failed to read PF status", "path", pathFile) 126 return nil, false, err 127 } 128 129 err = json.Unmarshal(data, pfStatus) 130 if err != nil { 131 log.Log.Error(err, "failed to unmarshal PF status", "data", string(data)) 132 return nil, false, err 133 } 134 135 return pfStatus, true, nil 136 } 137 138 func (s *manager) GetCheckPointNodeState() (*sriovnetworkv1.SriovNetworkNodeState, error) { 139 log.Log.Info("getCheckPointNodeState()") 140 configdir := filepath.Join(vars.Destdir, consts.CheckpointFileName) 141 file, err := os.OpenFile(configdir, os.O_RDONLY, 0644) 142 if err != nil { 143 if os.IsNotExist(err) { 144 return nil, nil 145 } 146 return nil, err 147 } 148 defer file.Close() 149 if err = json.NewDecoder(file).Decode(&sriovnetworkv1.InitialState); err != nil { 150 return nil, err 151 } 152 153 return &sriovnetworkv1.InitialState, nil 154 } 155 156 func (s *manager) WriteCheckpointFile(ns *sriovnetworkv1.SriovNetworkNodeState) error { 157 configdir := filepath.Join(vars.Destdir, consts.CheckpointFileName) 158 file, err := os.OpenFile(configdir, os.O_RDWR|os.O_CREATE, 0644) 159 if err != nil { 160 return err 161 } 162 defer file.Close() 163 log.Log.Info("WriteCheckpointFile(): try to decode the checkpoint file") 164 if err = json.NewDecoder(file).Decode(&sriovnetworkv1.InitialState); err != nil { 165 log.Log.V(2).Error(err, "WriteCheckpointFile(): fail to decode, writing new file instead") 166 log.Log.Info("WriteCheckpointFile(): write checkpoint file") 167 if err = file.Truncate(0); err != nil { 168 return err 169 } 170 if _, err = file.Seek(0, 0); err != nil { 171 return err 172 } 173 if err = json.NewEncoder(file).Encode(*ns); err != nil { 174 return err 175 } 176 sriovnetworkv1.InitialState = *ns 177 } 178 return nil 179 }