You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
3.3 KiB

3 months ago
3 years ago
  1. package shell
  2. import (
  3. "context"
  4. "flag"
  5. "fmt"
  6. "github.com/seaweedfs/seaweedfs/weed/filer"
  7. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  8. "github.com/seaweedfs/seaweedfs/weed/remote_storage"
  9. "github.com/seaweedfs/seaweedfs/weed/util"
  10. "io"
  11. "time"
  12. )
  13. func init() {
  14. Commands = append(Commands, &commandRemoteUnmount{})
  15. }
  16. type commandRemoteUnmount struct {
  17. }
  18. func (c *commandRemoteUnmount) Name() string {
  19. return "remote.unmount"
  20. }
  21. func (c *commandRemoteUnmount) Help() string {
  22. return `unmount remote storage
  23. # assume a remote storage is configured to name "s3_1"
  24. remote.configure -name=s3_1 -type=s3 -s3.access_key=xxx -s3.secret_key=yyy
  25. # mount and pull one bucket
  26. remote.mount -dir=/xxx -remote=s3_1/bucket
  27. # unmount the mounted directory and remove its cache
  28. remote.unmount -dir=/xxx
  29. `
  30. }
  31. func (c *commandRemoteUnmount) HasTag(CommandTag) bool {
  32. return false
  33. }
  34. func (c *commandRemoteUnmount) Do(args []string, commandEnv *CommandEnv, writer io.Writer) (err error) {
  35. remoteMountCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
  36. dir := remoteMountCommand.String("dir", "", "a directory in filer")
  37. if err = remoteMountCommand.Parse(args); err != nil {
  38. return nil
  39. }
  40. mappings, listErr := filer.ReadMountMappings(commandEnv.option.GrpcDialOption, commandEnv.option.FilerAddress)
  41. if listErr != nil {
  42. return listErr
  43. }
  44. if *dir == "" {
  45. return jsonPrintln(writer, mappings)
  46. }
  47. _, found := mappings.Mappings[*dir]
  48. if !found {
  49. return fmt.Errorf("directory %s is not mounted", *dir)
  50. }
  51. // store a mount configuration in filer
  52. fmt.Fprintf(writer, "deleting mount for %s ...\n", *dir)
  53. if err = filer.DeleteMountMapping(commandEnv, *dir); err != nil {
  54. return fmt.Errorf("delete mount mapping: %v", err)
  55. }
  56. // purge mounted data
  57. fmt.Fprintf(writer, "purge %s ...\n", *dir)
  58. if err = c.purgeMountedData(commandEnv, *dir); err != nil {
  59. return fmt.Errorf("purge mounted data: %v", err)
  60. }
  61. // reset remote sync offset in case the folder is mounted again
  62. if err = remote_storage.SetSyncOffset(commandEnv.option.GrpcDialOption, commandEnv.option.FilerAddress, *dir, time.Now().UnixNano()); err != nil {
  63. return fmt.Errorf("reset remote.sync offset for %s: %v", *dir, err)
  64. }
  65. return nil
  66. }
  67. func (c *commandRemoteUnmount) purgeMountedData(commandEnv *CommandEnv, dir string) error {
  68. // find existing directory, and ensure the directory is empty
  69. err := commandEnv.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  70. parent, name := util.FullPath(dir).DirAndName()
  71. lookupResp, lookupErr := client.LookupDirectoryEntry(context.Background(), &filer_pb.LookupDirectoryEntryRequest{
  72. Directory: parent,
  73. Name: name,
  74. })
  75. if lookupErr != nil {
  76. return fmt.Errorf("lookup %s: %v", dir, lookupErr)
  77. }
  78. oldEntry := lookupResp.Entry
  79. deleteError := filer_pb.DoRemove(client, parent, name, true, true, true, false, nil)
  80. if deleteError != nil {
  81. return fmt.Errorf("delete %s: %v", dir, deleteError)
  82. }
  83. mkdirErr := filer_pb.DoMkdir(client, parent, name, func(entry *filer_pb.Entry) {
  84. entry.Attributes = oldEntry.Attributes
  85. entry.Extended = oldEntry.Extended
  86. entry.Attributes.Crtime = time.Now().Unix()
  87. entry.Attributes.Mtime = time.Now().Unix()
  88. })
  89. if mkdirErr != nil {
  90. return fmt.Errorf("mkdir %s: %v", dir, mkdirErr)
  91. }
  92. return nil
  93. })
  94. if err != nil {
  95. return err
  96. }
  97. return nil
  98. }