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.

153 lines
4.4 KiB

  1. package shell
  2. import (
  3. "context"
  4. "flag"
  5. "fmt"
  6. "github.com/chrislusf/seaweedfs/weed/filer"
  7. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  8. "github.com/chrislusf/seaweedfs/weed/pb/remote_pb"
  9. "github.com/chrislusf/seaweedfs/weed/util"
  10. "io"
  11. )
  12. func init() {
  13. Commands = append(Commands, &commandRemoteUnmount{})
  14. }
  15. type commandRemoteUnmount struct {
  16. }
  17. func (c *commandRemoteUnmount) Name() string {
  18. return "remote.unmount"
  19. }
  20. func (c *commandRemoteUnmount) Help() string {
  21. return `unmount remote storage
  22. # assume a remote storage is configured to name "s3_1"
  23. remote.configure -name=s3_1 -type=s3 -access_key=xxx -secret_key=yyy
  24. # mount and pull one bucket
  25. remote.mount -dir=/xxx -remote=s3_1/bucket
  26. # unmount the mounted directory and remove its cache
  27. # Make sure you have stopped "weed filer.remote.sync" first!
  28. # Otherwise, the deletion will also be propagated to the remote storage!!!
  29. remote.unmount -dir=/xxx -iHaveStoppedRemoteSync
  30. `
  31. }
  32. func (c *commandRemoteUnmount) Do(args []string, commandEnv *CommandEnv, writer io.Writer) (err error) {
  33. remoteMountCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
  34. dir := remoteMountCommand.String("dir", "", "a directory in filer")
  35. hasStoppedRemoteSync := remoteMountCommand.Bool("iHaveStoppedRemoteSync", false, "confirm to stop weed filer.remote.sync first")
  36. if err = remoteMountCommand.Parse(args); err != nil {
  37. return nil
  38. }
  39. mappings, listErr := filer.ReadMountMappings(commandEnv.option.GrpcDialOption, commandEnv.option.FilerAddress)
  40. if listErr != nil {
  41. return listErr
  42. }
  43. if *dir == "" {
  44. return jsonPrintln(writer, mappings)
  45. }
  46. _, found := mappings.Mappings[*dir]
  47. if !found {
  48. return fmt.Errorf("directory %s is not mounted", *dir)
  49. }
  50. if !*hasStoppedRemoteSync {
  51. return fmt.Errorf("make sure \"weed filer.remote.sync\" is stopped to avoid data loss")
  52. }
  53. // purge mounted data
  54. if err = c.purgeMountedData(commandEnv, *dir); err != nil {
  55. return fmt.Errorf("purge mounted data: %v", err)
  56. }
  57. // store a mount configuration in filer
  58. if err = c.deleteMountMapping(commandEnv, *dir); err != nil {
  59. return fmt.Errorf("delete mount mapping: %v", err)
  60. }
  61. return nil
  62. }
  63. func (c *commandRemoteUnmount) findRemoteStorageConfiguration(commandEnv *CommandEnv, writer io.Writer, remote *remote_pb.RemoteStorageLocation) (conf *remote_pb.RemoteConf, err error) {
  64. return filer.ReadRemoteStorageConf(commandEnv.option.GrpcDialOption, commandEnv.option.FilerAddress, remote.Name)
  65. }
  66. func (c *commandRemoteUnmount) purgeMountedData(commandEnv *CommandEnv, dir string) error {
  67. // find existing directory, and ensure the directory is empty
  68. err := commandEnv.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  69. parent, name := util.FullPath(dir).DirAndName()
  70. lookupResp, lookupErr := client.LookupDirectoryEntry(context.Background(), &filer_pb.LookupDirectoryEntryRequest{
  71. Directory: parent,
  72. Name: name,
  73. })
  74. if lookupErr != nil {
  75. return fmt.Errorf("lookup %s: %v", dir, lookupErr)
  76. }
  77. oldEntry := lookupResp.Entry
  78. deleteError := filer_pb.DoRemove(client, parent, name, true, true, true, false, nil)
  79. if deleteError != nil {
  80. return fmt.Errorf("delete %s: %v", dir, deleteError)
  81. }
  82. mkdirErr := filer_pb.DoMkdir(client, parent, name, func(entry *filer_pb.Entry) {
  83. entry.Attributes = oldEntry.Attributes
  84. entry.Extended = oldEntry.Extended
  85. })
  86. if mkdirErr != nil {
  87. return fmt.Errorf("mkdir %s: %v", dir, mkdirErr)
  88. }
  89. return nil
  90. })
  91. if err != nil {
  92. return err
  93. }
  94. return nil
  95. }
  96. func (c *commandRemoteUnmount) deleteMountMapping(commandEnv *CommandEnv, dir string) (err error) {
  97. // read current mapping
  98. var oldContent, newContent []byte
  99. err = commandEnv.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  100. oldContent, err = filer.ReadInsideFiler(client, filer.DirectoryEtcRemote, filer.REMOTE_STORAGE_MOUNT_FILE)
  101. return err
  102. })
  103. if err != nil {
  104. if err != filer_pb.ErrNotFound {
  105. return fmt.Errorf("read existing mapping: %v", err)
  106. }
  107. }
  108. // add new mapping
  109. newContent, err = filer.RemoveRemoteStorageMapping(oldContent, dir)
  110. if err != nil {
  111. return fmt.Errorf("delete mount %s: %v", dir, err)
  112. }
  113. // save back
  114. err = commandEnv.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  115. return filer.SaveInsideFiler(client, filer.DirectoryEtcRemote, filer.REMOTE_STORAGE_MOUNT_FILE, newContent)
  116. })
  117. if err != nil {
  118. return fmt.Errorf("save mapping: %v", err)
  119. }
  120. return nil
  121. }