github.com/whamcloud/lemur@v0.0.0-20190827193804-4655df8a52af/cmd/lhsmd/agent/snapshot.go (about)

     1  // Copyright (c) 2018 DDN. All rights reserved.
     2  // Use of this source code is governed by a MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package agent
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"path"
    11  	"time"
    12  
    13  	"github.com/pkg/errors"
    14  
    15  	"github.com/intel-hpdd/go-lustre"
    16  	"github.com/intel-hpdd/go-lustre/fs"
    17  	"github.com/intel-hpdd/go-lustre/hsm"
    18  	"github.com/intel-hpdd/go-lustre/llapi"
    19  	"github.com/intel-hpdd/go-lustre/status"
    20  	"github.com/intel-hpdd/lemur/cmd/lhsmd/agent/fileid"
    21  	"github.com/intel-hpdd/logging/alert"
    22  	"github.com/intel-hpdd/logging/debug"
    23  )
    24  
    25  func createSnapDir(p string) (string, error) {
    26  	fi, err := os.Lstat(p)
    27  	if err != nil {
    28  		return "", errors.Wrap(err, "lstat failed")
    29  	}
    30  	snapDir := path.Join(p, ".hsmsnap")
    31  	err = os.MkdirAll(snapDir, fi.Mode())
    32  	if err != nil {
    33  		return "", errors.Wrap(err, "mkdir all failed")
    34  	}
    35  	return snapDir, nil
    36  }
    37  
    38  func createStubFile(f string, fi os.FileInfo, archive uint, layout *llapi.DataLayout) error {
    39  	_, err := hsm.Import(f, archive, fi, layout)
    40  	if err != nil {
    41  		os.Remove(f)
    42  		return errors.Wrapf(err, "%s: import failed", f)
    43  	}
    44  	return nil
    45  }
    46  
    47  func snapName(fi os.FileInfo) string {
    48  	return fmt.Sprintf("%s^%s", fi.Name(), fi.ModTime().Format(time.RFC3339))
    49  }
    50  
    51  func createSnapshots(mnt fs.RootDir, archive uint, fileID []byte, names []string) error {
    52  	var firstPath string
    53  	first := true
    54  	for _, p := range names {
    55  		absPath := mnt.Join(p)
    56  		snapDir, err := createSnapDir(path.Dir(absPath))
    57  		if err != nil {
    58  			return errors.Wrap(err, "create snapdir failed")
    59  		}
    60  		fi, err := os.Lstat(absPath)
    61  		if err != nil {
    62  			return errors.Wrap(err, "lstat failed")
    63  		}
    64  		f := path.Join(snapDir, snapName(fi))
    65  		if first {
    66  			var layout *llapi.DataLayout
    67  			layout, err = llapi.FileDataLayout(absPath)
    68  			if err != nil {
    69  				alert.Warnf("%s: unable to get layout: %v", f, err)
    70  				return errors.Wrap(err, "get layout")
    71  			}
    72  			debug.Printf("%s: layout: %#v", absPath, layout)
    73  			err = createStubFile(f, fi, archive, layout)
    74  			if err != nil {
    75  				return errors.Wrap(err, "create stub file")
    76  			}
    77  			err = fileid.UUID.Set(f, fileID)
    78  			if err != nil {
    79  				return errors.Wrapf(err, "%s: set fileid", f)
    80  			}
    81  			firstPath = f
    82  			first = false
    83  		} else {
    84  			err = os.Link(firstPath, f)
    85  			if err != nil {
    86  				return errors.Wrapf(err, "%s: link to %s failed", f, firstPath)
    87  			}
    88  		}
    89  
    90  	}
    91  	return nil
    92  }
    93  
    94  func createSnapshot(mnt fs.RootDir, archive uint, fid *lustre.Fid, fileID []byte) error {
    95  	names, err := status.FidPathnames(mnt, fid)
    96  	if err != nil {
    97  		return errors.Wrapf(err, "%s: fidpathname failed", fid)
    98  	}
    99  
   100  	return createSnapshots(mnt, archive, fileID, names)
   101  }