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.

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