remotefs.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // +build windows
  2. package lcow
  3. import (
  4. "bytes"
  5. "fmt"
  6. "io"
  7. "runtime"
  8. "strings"
  9. "sync"
  10. "github.com/Microsoft/hcsshim"
  11. "github.com/Microsoft/opengcs/service/gcsutils/remotefs"
  12. "github.com/docker/docker/pkg/archive"
  13. "github.com/docker/docker/pkg/containerfs"
  14. "github.com/sirupsen/logrus"
  15. )
  16. type lcowfs struct {
  17. root string
  18. d *Driver
  19. mappedDisks []hcsshim.MappedVirtualDisk
  20. vmID string
  21. currentSVM *serviceVM
  22. sync.Mutex
  23. }
  24. var _ containerfs.ContainerFS = &lcowfs{}
  25. // ErrNotSupported is an error for unsupported operations in the remotefs
  26. var ErrNotSupported = fmt.Errorf("not supported")
  27. // Functions to implement the ContainerFS interface
  28. func (l *lcowfs) Path() string {
  29. return l.root
  30. }
  31. func (l *lcowfs) ResolveScopedPath(path string, rawPath bool) (string, error) {
  32. logrus.Debugf("remotefs.resolvescopedpath inputs: %s %s ", path, l.root)
  33. arg1 := l.Join(l.root, path)
  34. if !rawPath {
  35. // The l.Join("/", path) will make path an absolute path and then clean it
  36. // so if path = ../../X, it will become /X.
  37. arg1 = l.Join(l.root, l.Join("/", path))
  38. }
  39. arg2 := l.root
  40. output := &bytes.Buffer{}
  41. if err := l.runRemoteFSProcess(nil, output, remotefs.ResolvePathCmd, arg1, arg2); err != nil {
  42. return "", err
  43. }
  44. logrus.Debugf("remotefs.resolvescopedpath success. Output: %s\n", output.String())
  45. return output.String(), nil
  46. }
  47. func (l *lcowfs) OS() string {
  48. return "linux"
  49. }
  50. func (l *lcowfs) Architecture() string {
  51. return runtime.GOARCH
  52. }
  53. // Other functions that are used by docker like the daemon Archiver/Extractor
  54. func (l *lcowfs) ExtractArchive(src io.Reader, dst string, opts *archive.TarOptions) error {
  55. logrus.Debugf("remotefs.ExtractArchve inputs: %s %+v", dst, opts)
  56. tarBuf := &bytes.Buffer{}
  57. if err := remotefs.WriteTarOptions(tarBuf, opts); err != nil {
  58. return fmt.Errorf("failed to marshall tar opts: %s", err)
  59. }
  60. input := io.MultiReader(tarBuf, src)
  61. if err := l.runRemoteFSProcess(input, nil, remotefs.ExtractArchiveCmd, dst); err != nil {
  62. return fmt.Errorf("failed to extract archive to %s: %s", dst, err)
  63. }
  64. return nil
  65. }
  66. func (l *lcowfs) ArchivePath(src string, opts *archive.TarOptions) (io.ReadCloser, error) {
  67. logrus.Debugf("remotefs.ArchivePath: %s %+v", src, opts)
  68. tarBuf := &bytes.Buffer{}
  69. if err := remotefs.WriteTarOptions(tarBuf, opts); err != nil {
  70. return nil, fmt.Errorf("failed to marshall tar opts: %s", err)
  71. }
  72. r, w := io.Pipe()
  73. go func() {
  74. defer w.Close()
  75. if err := l.runRemoteFSProcess(tarBuf, w, remotefs.ArchivePathCmd, src); err != nil {
  76. logrus.Debugf("REMOTEFS: Failed to extract archive: %s %+v %s", src, opts, err)
  77. }
  78. }()
  79. return r, nil
  80. }
  81. // Helper functions
  82. func (l *lcowfs) startVM() error {
  83. l.Lock()
  84. defer l.Unlock()
  85. if l.currentSVM != nil {
  86. return nil
  87. }
  88. svm, err := l.d.startServiceVMIfNotRunning(l.vmID, l.mappedDisks, fmt.Sprintf("lcowfs.startVM"))
  89. if err != nil {
  90. return err
  91. }
  92. if err = svm.createUnionMount(l.root, l.mappedDisks...); err != nil {
  93. return err
  94. }
  95. l.currentSVM = svm
  96. return nil
  97. }
  98. func (l *lcowfs) runRemoteFSProcess(stdin io.Reader, stdout io.Writer, args ...string) error {
  99. if err := l.startVM(); err != nil {
  100. return err
  101. }
  102. // Append remotefs prefix and setup as a command line string
  103. cmd := fmt.Sprintf("%s %s", remotefs.RemotefsCmd, strings.Join(args, " "))
  104. stderr := &bytes.Buffer{}
  105. if err := l.currentSVM.runProcess(cmd, stdin, stdout, stderr); err != nil {
  106. return err
  107. }
  108. eerr, err := remotefs.ReadError(stderr)
  109. if eerr != nil {
  110. // Process returned an error so return that.
  111. return remotefs.ExportedToError(eerr)
  112. }
  113. return err
  114. }