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  }