pax_global_header 0000666 0000000 0000000 00000000064 14044051046 0014510 g ustar 00root root 0000000 0000000 52 comment=0f5c864606b5b5eae003b5233e1f6092fb5fea3b
.gitignore 0000664 0000000 0000000 00000000222 14044051046 0013040 0 ustar 00root root 0000000 0000000 # Build artifacts
pkg
build
# Ruby / Bundler
Gemfile.lock
.ruby-gemset
.ruby-version
# .vagrant dirs
.vagrant
# IDE config files
.idea
*.iml
Gemfile 0000664 0000000 0000000 00000001030 14044051046 0012341 0 ustar 00root root 0000000 0000000 source "https://rubygems.org"
gemspec
group :development do
# We depend on Vagrant for development, but we don't add it as a
# gem dependency because we expect to be installed within the
# Vagrant environment itself using `vagrant plugin`.
gem "vagrant", :git => "https://github.com/mitchellh/vagrant.git", :ref => 'v2.2.16'
end
group :plugins do
# Add vagrant-libvirt plugin here, otherwise you won't be able to
# use libvirt as a provider when you execute `bundle exec vagrant up`
gem "vagrant-libvirt" , '0.4.1'
end
LICENSE 0000664 0000000 0000000 00000043177 14044051046 0012075 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
README.adoc 0000664 0000000 0000000 00000024542 14044051046 0012650 0 ustar 00root root 0000000 0000000 = vagrant-sshfs
:toc:
:toc-placement!:
This Vagrant plugin adds synced folder support for mounting
folders from the Vagrant host into the Vagrant guest via
https://github.com/libfuse/sshfs[SSHFS]. In the default mode it does
this by executing the `SSHFS` client software within the guest, which
creates an SSH connection from the Vagrant guest back to the Vagrant
host.
'''
toc::[]
'''
[[considerations]]
== Considerations
The benefits of this approach:
* Works on any host platform and hypervisor type
** Windows, Linux, Mac OS X
** Virtualbox, Libvirt, Hyper-V, VMWare
* Seamlessly works on remote Vagrant solutions
** Works with vagrant aws/openstack/etc.. plugins
The drawbacks with this approach:
* Performance is worse than an implementation like NFS
* There must be `sftp-server` software on the Vagrant host
`sftp-server` is usually provided by SSH server software so it already
exists on Linux/Mac. On windows you only need to install
https://cygwin.com/cgi-bin2/package-grep.cgi?grep=openssh&arch=x86_64[openssh]
via https://cygwin.com/[cygwin] and you will get `sftp-server`.
Also, we recommend running vagrant from the cygwin provided terminal. There have
been issues with other shells leading to problems with mounts.
[[history]]
== History
The inspiration for this plugin came from
https://github.com/fabiokr[Fabio Kreusch] and his
https://github.com/fabiokr/vagrant-sshfs[code] for the original
vagrant-sshfs Vagrant plugin. The goal of this plugin (as opposed to the
old implementation) is to implement SSHFS as a synced folder plugin just
like the other synced folder plugins (NFS/RSYNC/SMB/VirtualBox).
This plugin was developed mainly by copying the code from the NFS synced
folder plugin from the Vagrant core code and molding it to fit SSHFS.
[[modes-of-operation]]
== Modes of Operation
[[sharing-vagrant-host-directory-to-vagrant-guest---94-of-users]]
=== Sharing Vagrant Host Directory to Vagrant Guest - 94% of users
This plugin uses SSHFS slave mounts (see
https://github.com/dustymabe/vagrant-sshfs/issues/11[link]) to mount a
directory from the Vagrant Host into the Vagrant Guest. It uses the
`sftp-server` software that exists on the host and `sshfs` running in
_slave mode_ within the guest to create a connection using the existing
authentication over SSH that vagrant sets up for you.
[[sharing-arbitrary-host-directory-to-vagrant-guest---1-of-users]]
=== Sharing Arbitrary Host Directory to Vagrant Guest - 1% of users
This plugin allows you to share a folder from an arbitrary host to the
Vagrant Guest. This would allow you to do a folder mount to some other
host that may have files that you need. To do this the plugin will run
an SSHFS command from the Guest and connect to the arbitrary host that
must have an SSH daemon running. You must provide the `ssh_host` option
in the Vagrantfile to get this to work. You can use ssh key forwarding
or username/password for authentication for this.
See link:#options-specific-to-arbitrary-host-mounting[Options] and
link:#appendix-a-using-keys-and-forwarding-ssh-agent[Appendix A] for
more information.
[[sharing-vagrant-guest-directory-to-vagrant-host---5-of-users]]
=== Sharing Vagrant Guest Directory to Vagrant Host - 5% of users
_NOTE:_ This option is dangerous as data will be destroyed upon
`vagrant destroy`
This plugin allows you to share a folder from a Vagrant guest into the
host. If you have workloads where there are a lot of disk intensive
operations (such as compilation) it may be ideal to have the files live
in the guest where the disk intensive operations would occur. For
discussion see https://github.com/dustymabe/vagrant-sshfs/issues/7[Issue
#7].
See link:#options-specific-to-reverse-mounting-guest-host-mount[Options]
for more information on how to enable this type of mount.
[[getting-started]]
== Getting Started
In order to use this synced folder implementation perform the following
steps:
[[install-plugin]]
=== Install Plugin
In order to install the plugin simply run the following command:
....
# vagrant plugin install vagrant-sshfs
....
[[add-sshfs-synced-folder-in-vagrantfile]]
=== Add SSHFS Synced Folder in Vagrantfile
Edit your Vagrantfile to specify a folder to mount from the host into
the guest:
....
config.vm.synced_folder "/path/on/host", "/path/on/guest", type: "sshfs"
....
Now you can simply `vagrant up` and your folder should be mounted in the
guest. For more options that you can add see the link:#options[Options]
section.
[[executing-the-vagrant-sshfs-command]]
== Executing the `vagrant sshfs` Command
The Vagrant SSHFS plugin also supports execution of the `vagrant sshfs`
command from the command line. Executing this command with the `--mount`
option will iterate through the Vagrant file and attempt to mount (via
SSHFS) any folders that aren't already mounted in the Vagrant guest.
Executing with the `--unmount` option will unmount any mounted folders.
....
vagrant sshfs [--mount|--unmount] [vm-name]
....
[[options]]
== Options
The SSHFS synced folder plugin supports a few options that can be
provided in the `Vagrantfile`. The following sections describe the
options in more detail.
[[generic-options]]
=== Generic Options
The SSHFS synced folder plugin supports a few options that can be
provided in the `Vagrantfile`. They are described below:
* `disabled`
** If set to 'true', ignore this folder and don't mount it.
* `ssh_opts_append`
** Add some options for the ssh connection that will be established.
** See the ssh man page for more details on possible options.
* `sshfs_opts_append`
** Add some options for the sshfs fuse mount that will made
** See the sshfs man page for more details on possible options.
An example snippet from a `Vagrantfile`:
....
config.vm.synced_folder "/path/on/host", "/path/on/guest",
ssh_opts_append: "-o Compression=yes -o CompressionLevel=5",
sshfs_opts_append: "-o auto_cache -o cache_timeout=115200",
disabled: false, type: "sshfs"
....
[[options-specific-to-arbitrary-host-mounting]]
=== Options Specific to Arbitrary Host Mounting
The following options are only to be used when
link:#sharing-arbitrary-host-directory-to-vagrant-guest---1-of-users[sharing
an arbitrary host directory] with the guest. They will be ignored
otherwise:
* `ssh_host`
** The host to connect to via SSH. If not provided this will be detected
as the Vagrant host that is running the Vagrant guest.
* `ssh_port`
** The port to use when connecting. Defaults to port 22.
* `ssh_username`
** The username to use when connecting. If not provided it is detected
as the current user who is interacting with Vagrant.
* `ssh_password`
** The password to use when connecting. If not provided and the user is
not using SSH keys, then the user will be prompted for the password.
Please use SSH keys and don't use this option!
* `prompt_for_password`
** The user can force Vagrant to interactively prompt the user for a
password by setting this to 'true'. Alternatively the user can deny
Vagrant from ever prompting for the password by setting this to 'false'.
An example snippet from a `Vagrantfile`:
....
config.vm.synced_folder "/path/on/host", "/path/on/guest",
ssh_host: "somehost.com", ssh_username: "fedora",
ssh_opts_append: "-o Compression=yes -o CompressionLevel=5",
sshfs_opts_append: "-o auto_cache -o cache_timeout=115200",
disabled: false, type: "sshfs"
....
[[options-specific-to-reverse-mounting-guest-host-mount]]
=== Options Specific to Reverse Mounting (Guest->Host Mount)
If your host has the `sshfs` software installed then the following
options enable mounting a folder from a Vagrant Guest into the Vagrant
Host:
* `reverse`
** This can be set to 'true' to enable reverse mounting a guest folder
into the Vagrant host.
An example snippet from a `Vagrantfile` where we want to mount `/data`
on the guest into `/guest/data` on the host:
....
config.vm.synced_folder "/guest/data", "/data", type: 'sshfs', reverse: true
....
[[faq]]
== FAQ
Here are some answers to some frequently asked questions:
[[why-do-new-files-take-time-to-appear-inside-the-guest]]
=== Why do new files take time to appear inside the guest?
Sometimes it can take time for files to appear on the other end of the
sshfs mount. An example would be I create a file on my host system and
then it doesn't show up inside the guest mount for 10 to 20 seconds.
This is because of caching that SSHFS does to improve performance.
Performance vs accuracy is always going to be a trade-off. If you'd like
to disable caching completely you can disable caching completely by
appending the `cache=no` SSHFS option to the synced folder definition in
the Vagrantfile like so:
....
config.vm.synced_folder "/path/on/host", "/path/on/guest",
type: "sshfs", sshfs_opts_append: "-o cache=no"
....
All caching options that are available to sshfs can be added/modified in
this same manner.
[[appendix-a-using-keys-and-forwarding-ssh-agent]]
== Appendix A: Using Keys and Forwarding SSH Agent
When
link:#sharing-arbitrary-host-directory-to-vagrant-guest---1-of-users[sharing
an arbitrary host directory] you may want a completely non-interactive
experience. You can either hard code your password in the Vagrantfile or
you can use SSH keys. A few guides for setting up ssh keys and key
forwarding are on Github:
* https://help.github.com/articles/generating-ssh-keys[Key Generation]
* https://developer.github.com/guides/using-ssh-agent-forwarding/[Key Forwarding]
The idea is that if `key1` is a key that is authorized to log in to the
Vagrant host ,meaning there is an entry for `key1` in the
`~/.ssh/authorized_keys` file, then you should be able to do the
following to have a non-interactive experience with SSH keys and agent
forwarding:
Modify the Vagrantfile to forward your SSH agent:
....
config.ssh.forward_agent = 'true'
....
Now set up your agent and add your key to the agent:
....
# eval $(ssh-agent)
# ssh-add /path/to/key1
....
And finally bring up your Vagrant guest:
....
# vagrant up
....
[[appendix-b-development]]
== Appendix B: Development
For local development of this plugin here is an example of how to build,
test and install this plugin on your local machine:
....
# Install development dependencies
$ gem install bundler && bundle install
# Build the gem (gets generated in the 'pkg' directory
$ bundle exec rake build
# Run Vagrant in the context of the plugin
$ bundle exec vagrant
# Install built gem into global Vagrant installation (run outside of git checkout!)
$ vagrant plugin install
....
RELEASE.txt 0000664 0000000 0000000 00000003401 14044051046 0012673 0 ustar 00root root 0000000 0000000
# point local system to git for vagrant-sshfs
- cd /usr/share/vagrant/gems/gems
- sudo mv vagrant-sshfs-1.3.3 vsshfs133
- sudo ln -s /var/b/shared/code/github.com/dustymabe/vagrant-sshfs ./vagrant-sshfs-1.3.3
# Run misc tests
cd /var/b/shared/code/github.com/dustymabe/vagrant-sshfs/test/misc
follow README for running tests
# Make sure to bump version in lib/vagrant-sshfs/version.rb and commit
# DO NOT TAG YET
# Craft a commit message for the tag.
LASTTAG='v1.3.1'
VERSION='1.3.2'
NEWTAG="v${VERSION}"
cat < release-notes.txt
This is release ${NEWTAG} of the vagrant-sshfs plugin.
Thanks to the following contributors for patches during this release:
$(git shortlog --no-merges --pretty=format:"%h %s" -e ${LASTTAG}..HEAD)
EOF
# After crafting message then install git-evtag and sign
git-evtag sign ${NEWTAG}
close and type in password for signing
verify with git-evtag verify ${NEWTAG}
verify with git verify-tag ${NEWTAG}
git push
git push --tags
# Build with build.sh script (uses buildah)
# We must run it in a buildah unshare session. Otherwise we get the error:
#
# ++ buildah mount fedora-working-container
# cannot mount using driver overlay in rootless mode. You need to run it in a `buildah unshare` session
buildah unshare ./build.sh
# Sign the output (This will create a .asc file)
gpg2 --armor --detach-sign ./vagrant-sshfs-${VERSION}.gem
# make tar.gz and zip files
git archive --format=tar.gz ${NEWTAG} > vagrant-sshfs-${VERSION}.tar.gz
gpg2 --armor --detach-sign vagrant-sshfs-${VERSION}.tar.gz
git archive --format=zip ${NEWTAG} > vagrant-sshfs-${VERSION}.zip
gpg2 --armor --detach-sign vagrant-sshfs-${VERSION}.zip
# Update release notes and upload files on github
# push to rubygems with:
gem push ./vagrant-sshfs-${VERSION}.gem
Rakefile 0000664 0000000 0000000 00000001461 14044051046 0012523 0 ustar 00root root 0000000 0000000 # A Rakefile is like a Makefile for ruby
# bundler/gem_tasks provides functionality like:
# bundle exec rake build
# bundle exec rake install
# bundle exec rake release
#
require 'bundler/gem_tasks'
# rake/clean provides CLEAN/CLOBBER
# http://www.virtuouscode.com/2014/04/28/rake-part-6-clean-and-clobber/
# CLEAN - list to let rake know what files can be cleaned up after build
# CLOBBER - list to let rake know what files are final products of the build
#
require 'rake/clean'
# Add the build dir to the list of items to clean up
CLEAN.include('build')
# We want to keep the build artifacts in the pkg dir
CLOBBER.include('pkg')
# Define a Rake::Task that will do initialization for us
# See http://www.ultrasaurus.com/2009/12/creating-a-custom-rake-task/
task :init do
FileUtils.mkdir_p 'build'
end
build.sh 0000775 0000000 0000000 00000002374 14044051046 0012520 0 ustar 00root root 0000000 0000000 #!/bin/bash -x
set -ex
ctr=$(buildah from registry.fedoraproject.org/fedora:33)
rpms=(
make gcc ruby ruby-devel redhat-rpm-config # for building gems
gcc-c++ # for building unf_ext
libvirt-devel # for building ruby-libvirt gem
zlib-devel # for building nokogiri gem
git # for the git ls-files in gemspec file
bsdtar # used by vagrant to unpack box files
)
WORKINGDIR='/tmp/workingdir/'
# Set working directory
buildah config --workingdir $WORKINGDIR $ctr
# Get all updates and install needed rpms
buildah run $ctr -- dnf update -y
buildah run $ctr -- dnf install -y ${rpms[@]}
# Add source code
buildah add $ctr './' $WORKINGDIR
# Install bundler
buildah run $ctr -- gem install bundler
# Install all needed gems
buildah run $ctr -- bundle install --with plugins
# Install all needed gems
buildah run $ctr -- bundle exec rake build
# Copy built files outside of container
mount=$(buildah mount $ctr)
package=$(ls $mount/$WORKINGDIR/pkg/vagrant-sshfs-*gem)
echo "copying to ./$(basename $package)"
cp $package ./
buildah umount $ctr
echo "Built package is at ./$(basename $package)"
lib/ 0000775 0000000 0000000 00000000000 14044051046 0011622 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs.rb 0000664 0000000 0000000 00000001547 14044051046 0014744 0 ustar 00root root 0000000 0000000 begin
require "vagrant"
rescue LoadError
raise "The Vagrant sshfs plugin must be run within Vagrant"
end
# Only load the gem on Windows since it replaces some methods in Ruby's
# Process class. Also load it here before Process.uid is called the first
# time by Vagrant. The Process.create() function actually gets used in
# lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb
if Vagrant::Util::Platform.windows?
require 'win32/process'
end
require "vagrant-sshfs/errors"
require "vagrant-sshfs/version"
require "vagrant-sshfs/plugin"
module VagrantPlugins
module SyncedFolderSSHFS
# Returns the path to the source of this plugin
def self.source_root
@source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
end
I18n.load_path << File.expand_path('locales/synced_folder_sshfs.yml', source_root)
I18n.reload!
end
end
lib/vagrant-sshfs/ 0000775 0000000 0000000 00000000000 14044051046 0014410 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/action_hostpath_fixup.rb 0000664 0000000 0000000 00000010235 14044051046 0021340 0 ustar 00root root 0000000 0000000 require "log4r"
require "vagrant/action/builtin/mixin_synced_folders"
module VagrantPlugins
module SyncedFolderSSHFS
# Class that contains common function that are called by both
# HostPathFix and HostPathUnfix classes.
class HostPathFixCommon
include Vagrant::Action::Builtin::MixinSyncedFolders
def initialize()
@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs")
end
def fix(data)
# If this is an arbitrary host mount we need to set the hostpath
# to something that will pass the config checks that assume the
# hostpath is coming from the vagrant host and not from an arbitrary
# host. Save off the original hostpath and then set the hostpath to
# "." to pass the checks.
if data[:ssh_host]
data[:hostpath_orig] = data[:hostpath]
data[:hostpath] = "."
end
end
def unfix(data)
# If this is a reverse mounted folder or an arbitrary host mount
# then we'll set "hostpath_exact" so they don't try to create a
# folder on the host in Vagrant::Action::Builtin::SyncedFolders.
if data[:ssh_host]
data[:hostpath_exact] = true
data[:hostpath] = data[:hostpath_orig]
data.delete(:hostpath_orig)
end
end
# Loop through synced folder entries and either fix or unfix
# based on the fix arg
def loop_and_fix_unfix(env, fix)
opts = {
cached: !!env[:synced_folders_cached],
config: env[:synced_folders_config],
}
@logger.debug("SyncedFolders loading from cache: #{opts[:cached]}")
folders = synced_folders(env[:machine], **opts)
folders.each do |impl_name, fs|
next if impl_name != :sshfs
@logger.debug("Synced Folder Implementation: #{impl_name}")
fs.each do |id, data|
# replace data with a copy since we may delete/add new data to the config
data = data.dup
if fix
@logger.debug("fixup host path before: - #{id}: #{data[:hostpath]} => #{data[:guestpath]}")
fix(data)
@logger.debug("fixup host path after: - #{id}: #{data[:hostpath]} => #{data[:guestpath]}")
else
@logger.debug("unfixup host path before: - #{id}: #{data[:hostpath]} => #{data[:guestpath]}")
unfix(data)
@logger.debug("fixup host path after: - #{id}: #{data[:hostpath]} => #{data[:guestpath]}")
end
# Replace the entry in the config with the updated one
env[:machine].config.vm.synced_folders.delete(id)
env[:machine].config.vm.synced_folder(
data[:hostpath],
data[:guestpath],
data)
end
end
end
end
# Class that will massage the data for synced folders that are
# arbitrary host mounts (contain ssh_host in the options) to make
# it so that "host path checking" isn't performed on the vagrant
# host machine
class HostPathFix
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs")
end
def call(env)
classname = "VagrantPlugins::SyncedFolderSSHFS::HostPathFix"
@logger.debug("Executing hook within #{classname}")
# This part is for the IN action call
HostPathFixCommon.new().loop_and_fix_unfix(env, fix=true)
# Now continue until the OUT call
@app.call(env)
end
end
# Class that will undo the data manipulation that was done in
# HostPathFix and also set hostpath_exact=true if necessary
class HostPathUnfix
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs")
end
def call(env)
classname = "VagrantPlugins::SyncedFolderSSHFS::HostPathUnfix"
@logger.debug("Executing hook within #{classname}")
# This part is for the IN action call
HostPathFixCommon.new().loop_and_fix_unfix(env, fix=false)
# Now continue until the OUT call
@app.call(env)
end
end
end
end
lib/vagrant-sshfs/cap/ 0000775 0000000 0000000 00000000000 14044051046 0015153 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/ 0000775 0000000 0000000 00000000000 14044051046 0016302 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/alpine/ 0000775 0000000 0000000 00000000000 14044051046 0017552 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/alpine/sshfs_client.rb 0000664 0000000 0000000 00000001250 14044051046 0022561 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestAlpine
module Cap
class SSHFSClient
def self.sshfs_install(machine)
# Install sshfs
machine.communicate.sudo("apk add sshfs")
# Load the fuse module
machine.communicate.sudo("modprobe fuse")
end
def self.sshfs_installed(machine)
installed = machine.communicate.test("apk -e info sshfs")
if installed
# fuse may not get loaded at boot, so check if it's loaded otherwise force load it
machine.communicate.sudo("lsmod | grep fuse || modprobe fuse")
end
installed
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/arch/ 0000775 0000000 0000000 00000000000 14044051046 0017217 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/arch/sshfs_client.rb 0000664 0000000 0000000 00000002231 14044051046 0022226 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestArch
module Cap
class SSHFSClient
def self.sshfs_install(machine)
# Attempt to install sshfs but note that it may likely fail
# because the package file list is out of date (see [1]). A
# logical answer to this problem would be to update the
# package list and then install the package, but since arch
# doesn't support partial upgrades [2] that would require
# updating all packages in the system first. Not ideal
#
# [1] https://wiki.archlinux.org/index.php/pacman#Packages_cannot_be_retrieved_on_installation
# [2] https://wiki.archlinux.org/index.php/System_maintenance#Partial_upgrades_are_unsupported
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSInstallFailed
error_key = :install_failed_arch
cmd = "pacman --noconfirm -S sshfs"
machine.communicate.sudo(
cmd, error_class: error_class, error_key: error_key)
end
def self.sshfs_installed(machine)
machine.communicate.test("pacman -Q sshfs")
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/centos/ 0000775 0000000 0000000 00000000000 14044051046 0017575 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/centos/sshfs_client.rb 0000664 0000000 0000000 00000002255 14044051046 0022612 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestCentOS
module Cap
class SSHFSClient
def self.sshfs_install(machine)
case machine.guest.capability("flavor")
when :centos_8
# No need to install epel. fuse-sshfs comes from the powertools repo
# https://bugzilla.redhat.com/show_bug.cgi?id=1758884
# https://github.com/dustymabe/vagrant-sshfs/issues/123
machine.communicate.sudo("yum -y install --enablerepo=powertools fuse-sshfs")
when :centos_7, :centos # centos7 and centos6
# Install fuse-sshfs from epel
if !epel_installed(machine)
epel_install(machine)
end
machine.communicate.sudo("yum -y install fuse-sshfs")
end
end
def self.sshfs_installed(machine)
machine.communicate.test("rpm -q fuse-sshfs")
end
protected
def self.epel_installed(machine)
machine.communicate.test("rpm -q epel-release")
end
def self.epel_install(machine)
machine.communicate.sudo("yum -y install epel-release")
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/debian/ 0000775 0000000 0000000 00000000000 14044051046 0017524 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/debian/sshfs_client.rb 0000664 0000000 0000000 00000000601 14044051046 0022532 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestDebian
module Cap
class SSHFSClient
def self.sshfs_install(machine)
machine.communicate.sudo("apt-get update")
machine.communicate.sudo("apt-get install -y sshfs")
end
def self.sshfs_installed(machine)
machine.communicate.test("dpkg -l sshfs")
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/fedora/ 0000775 0000000 0000000 00000000000 14044051046 0017542 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/fedora/sshfs_client.rb 0000664 0000000 0000000 00000000521 14044051046 0022551 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestFedora
module Cap
class SSHFSClient
def self.sshfs_install(machine)
machine.communicate.sudo("dnf -y install fuse-sshfs")
end
def self.sshfs_installed(machine)
machine.communicate.test("rpm -q fuse-sshfs")
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/freebsd/ 0000775 0000000 0000000 00000000000 14044051046 0017714 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/freebsd/sshfs_client.rb 0000664 0000000 0000000 00000001174 14044051046 0022730 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestFreeBSD
module Cap
class SSHFSClient
def self.sshfs_install(machine)
machine.communicate.sudo("pkg install -y fusefs-sshfs")
machine.communicate.sudo("kldload fuse")
end
def self.sshfs_installed(machine)
installed = machine.communicate.test("pkg info fusefs-sshfs")
if installed
# fuse may not get loaded at boot, so check if it's loaded otherwise force load it
machine.communicate.sudo("kldstat -m fuse || kldload fuse")
end
installed
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/freebsd/sshfs_forward_mount.rb 0000664 0000000 0000000 00000000423 14044051046 0024334 0 ustar 00root root 0000000 0000000 require_relative "../linux/sshfs_forward_mount"
module VagrantPlugins
module GuestFreeBSD
module Cap
class MountSSHFS < VagrantPlugins::GuestLinux::Cap::MountSSHFS
def self.list_mounts_command
"mount -p"
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/linux/ 0000775 0000000 0000000 00000000000 14044051046 0017441 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/linux/sshfs_client.rb 0000664 0000000 0000000 00000000340 14044051046 0022447 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestLinux
module Cap
class SSHFSClient
def self.sshfs_installed(machine)
machine.communicate.test("test -x /usr/bin/sshfs")
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb 0000664 0000000 0000000 00000037771 14044051046 0024101 0 ustar 00root root 0000000 0000000 require "log4r"
require "vagrant/util/retryable"
require "vagrant/util/platform"
require "tempfile"
# This is already done for us in lib/vagrant-sshfs.rb. We needed to
# do it there before Process.uid is called the first time by Vagrant
# This provides a new Process.create() that works on Windows.
if Vagrant::Util::Platform.windows?
require 'win32/process'
end
module VagrantPlugins
module GuestLinux
module Cap
class MountSSHFS
extend Vagrant::Util::Retryable
@@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs_mount")
def self.list_mounts_command
"cat /proc/mounts"
end
def self.sshfs_forward_is_folder_mounted(machine, opts)
mounted = false
guest_path = opts[:guestpath]
# If the path doesn't exist at all in the machine then we
# can safely say it is not mounted
exists = machine.communicate.test("test -e #{guest_path}", sudo: true)
return false unless exists
# find the absolute path so that we can properly check if it is mounted
# https://github.com/dustymabe/vagrant-sshfs/issues/44
absolute_guest_path = machine.guest.capability(
:sshfs_get_absolute_path, guest_path)
# consult /proc/mounts to see if it is mounted or not
machine.communicate.execute(self.list_mounts_command) do |type, data|
if type == :stdout
data.each_line do |line|
if line.split()[1] == absolute_guest_path
mounted = true
break
end
end
end
end
return mounted
end
def self.sshfs_forward_mount_folder(machine, opts)
# opts contains something like:
# { :type=>:sshfs,
# :guestpath=>"/sharedfolder",
# :hostpath=>"/guests/sharedfolder",
# :disabled=>false
# :ssh_host=>"192.168.1.1"
# :ssh_port=>"22"
# :ssh_username=>"username"
# :ssh_password=>"password"
# }
# expand the guest path so we can handle things like "~/vagrant"
expanded_guest_path = machine.guest.capability(
:shell_expand_guest_path, opts[:guestpath])
# Create the mountpoint inside the guest
machine.communicate.tap do |comm|
comm.sudo("mkdir -p #{expanded_guest_path}")
comm.sudo("chmod 777 #{expanded_guest_path}")
end
# Mount path information: if arbitrary host mounting then
# take as is. If not, then expand the hostpath to the real
# path.
if opts[:ssh_host]
hostpath = opts[:hostpath].dup
else
hostpath = File.expand_path(opts[:hostpath], machine.env.root_path)
hostpath = Vagrant::Util::Platform.fs_real_path(hostpath).to_s
end
# Add in some sshfs/fuse options that are common to both mount methods
opts[:sshfs_opts] = ' -o allow_other ' # allow non-root users to access
opts[:sshfs_opts]+= ' -o noauto_cache '# disable caching based on mtime
# Add in some ssh options that are common to both mount methods
opts[:ssh_opts] = ' -o StrictHostKeyChecking=no '# prevent yes/no question
opts[:ssh_opts]+= ' -o ServerAliveInterval=30 ' # send keepalives
# Do a normal mount only if the user provided host information
if opts.has_key?(:ssh_host) and opts[:ssh_host]
self.sshfs_normal_mount(machine, opts, hostpath, expanded_guest_path)
else
self.sshfs_slave_mount(machine, opts, hostpath, expanded_guest_path)
end
end
def self.sshfs_forward_unmount_folder(machine, opts)
# opts contains something like:
# { :type=>:sshfs,
# :guestpath=>"/sharedfolder",
# :hostpath=>"/guests/sharedfolder",
# :disabled=>false
# :ssh_host=>"192.168.1.1"
# :ssh_port=>"22"
# :ssh_username=>"username"
# :ssh_password=>"password"
# }
# expand the guest path so we can handle things like "~/vagrant"
expanded_guest_path = machine.guest.capability(
:shell_expand_guest_path, opts[:guestpath])
# Log some information
machine.ui.info(I18n.t("vagrant.sshfs.actions.unmounting_folder",
guestpath: expanded_guest_path))
# Build up the command and connect
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSUnmountFailed
cmd = "umount #{expanded_guest_path}"
machine.communicate.sudo(
cmd, error_class: error_class, error_key: :unmount_failed)
end
protected
def self.windows_uninherit_handles(machine)
# For win32-process Process.create, if we pass any file handles to the
# underlying process for stdin/stdout/stderr then all file handles are
# inherited by default. We'll explicitly go through and set all Handles
# to not be inheritable by default. See following links for more info
#
# https://github.com/djberg96/win32-process/blob/6b380f450aebb69d44bb7accd958ecb6b9e1d246/lib/win32/process.rb#L445-L447
# bInheritHandles from https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
#
# In 6f285cd we made it so that we would uninherit all filehandles by
# default on windows. Some users have reported that this operation
# is erroring because `The parameter is incorrect.`. See #52
# We will make the uninheriting operation best effort. The rationale
# is that if a file handle was not able to be set to uninheritable
# then it probably wasn't one that would get inherited in the first place.
#
# For each open IO object
ObjectSpace.each_object(IO) do |io|
if !io.closed?
fileno = io.fileno
@@logger.debug("Setting file handle #{fileno} to not be inherited")
begin
self.windows_uninherit_handle(fileno)
rescue SystemCallError => error
msg = "Warning: couldn't set file handle #{fileno} to not be inherited\n"
msg+= "Message: " + error.message + "\n"
msg+= "Continuing in best effort...."
machine.ui.warn(msg)
@@logger.warn(msg)
end
end
end
end
def self.windows_uninherit_handle(fileno)
# Right now we'll be doing this using private methods from the win32-process
# module by calling For each open IO object. Much of this code was copied from
# that module. We access the private methods by using the object.send(:method, args)
# technique. In the future we want to get a patch upstream so we don't need to
# access private methods. Upstream request is here:
# https://github.com/djberg96/win32-process/pulls
# Get the windows IO handle and make sure we were successful getting it
handle = Process.send(:get_osfhandle, fileno)
if handle == Process::Constants::INVALID_HANDLE_VALUE
ptr = FFI::MemoryPointer.new(:int)
if Process.send(:windows_version) >= 6 && Process.get_errno(ptr) == 0
errno = ptr.read_int
else
errno = FFI.errno
end
raise SystemCallError.new("get_osfhandle", errno)
end
# Now clear the HANDLE_FLAG_INHERIT from the HANDLE so that the handle
# won't get shared by default. See:
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms724935(v=vs.85).aspx
#
bool = Process.send(:SetHandleInformation, handle,
Process::Constants::HANDLE_FLAG_INHERIT, 0)
raise SystemCallError.new("SetHandleInformation", FFI.errno) unless bool
end
# Perform a mount by running an sftp-server on the vagrant host
# and piping stdin/stdout to sshfs running inside the guest
def self.sshfs_slave_mount(machine, opts, hostpath, expanded_guest_path)
sftp_server_path = opts[:sftp_server_exe_path]
ssh_path = opts[:ssh_exe_path]
# SSH connection options
ssh_opts = opts[:ssh_opts]
ssh_opts_append = opts[:ssh_opts_append].to_s # provided by user
# SSHFS executable options
sshfs_opts = opts[:sshfs_opts]
sshfs_opts_append = opts[:sshfs_opts_append].to_s # provided by user
# The sftp-server command
sftp_server_cmd = sftp_server_path
# The remote sshfs command that will run (in slave mode)
sshfs_opts+= ' -o slave '
sshfs_cmd = "sudo -E sshfs :#{hostpath} #{expanded_guest_path}"
sshfs_cmd+= sshfs_opts + ' ' + sshfs_opts_append + ' '
# The ssh command to connect to guest and then launch sshfs
ssh_opts = opts[:ssh_opts]
ssh_opts+= ' -o User=' + machine.ssh_info[:username]
ssh_opts+= ' -o Port=' + machine.ssh_info[:port].to_s
ssh_opts+= ' -o UserKnownHostsFile=/dev/null '
ssh_opts+= ' -F /dev/null ' # Don't pick up options from user's config
if machine.ssh_info.key?(:private_key_path) and
machine.ssh_info[:private_key_path] and
machine.ssh_info[:private_key_path][0]
# Add IdentityFile since there is one
# Note the backslash escapes for IdentityFile - handles spaces in key path
ssh_opts+= ' -o "IdentityFile=\"' + machine.ssh_info[:private_key_path][0] + '\""'
end
# Use an SSH ProxyCommand when corresponding Vagrant setting is defined
if machine.ssh_info[:proxy_command]
ssh_opts+= " -o ProxyCommand=\"" + machine.ssh_info[:proxy_command] + "\""
end
ssh_cmd = ssh_path + ssh_opts + ' ' + ssh_opts_append + ' ' + machine.ssh_info[:host]
ssh_cmd+= ' "' + sshfs_cmd + '"'
# Log some information
@@logger.debug("sftp-server cmd: #{sftp_server_cmd}")
@@logger.debug("ssh cmd: #{ssh_cmd}")
machine.ui.info(I18n.t("vagrant.sshfs.actions.slave_mounting_folder",
hostpath: hostpath, guestpath: expanded_guest_path))
# Create two named pipes for communication between sftp-server and
# sshfs running in slave mode
r1, w1 = IO.pipe # reader/writer from pipe1
r2, w2 = IO.pipe # reader/writer from pipe2
# Log STDERR to predictable files so that we can inspect them
# later in case things go wrong. We'll use the machines data
# directory (i.e. .vagrant/machines/default/virtualbox/) for this
f1path = machine.data_dir.join('vagrant_sshfs_sftp_server_stderr.txt')
f2path = machine.data_dir.join('vagrant_sshfs_ssh_stderr.txt')
f1 = File.new(f1path, 'w+')
f2 = File.new(f2path, 'w+')
# The way this works is by hooking up the stdin+stdout of the
# sftp-server process to the stdin+stdout of the sshfs process
# running inside the guest in slave mode. An illustration is below:
#
# stdout => w1 pipe1 r1 => stdin
# />------------->==============>----------->\
# / \
# | |
# sftp-server (on vm host) sshfs (inside guest)
# | |
# \ /
# \<-------------<==============<-----------
# stdin <= r2 pipe2 w2 <= stdout
#
# Wire up things appropriately and start up the processes
if Vagrant::Util::Platform.windows?
# For windows we need to set it so not all file handles are inherited
# by default. See https://github.com/dustymabe/vagrant-sshfs/issues/41
# The r1,r2,w1,w2,f1,f2 we pass below will get set back to be shared
self.windows_uninherit_handles(machine)
# For windows, we are using win32-process' Process.create because ruby
# doesn't properly detach processes. See https://github.com/dustymabe/vagrant-sshfs/issues/31
Process.create(:command_line => sftp_server_cmd,
:creation_flags => Process::DETACHED_PROCESS,
:process_inherit => false,
:thread_inherit => true,
:startup_info => {:stdin => w2, :stdout => r1, :stderr => f1})
Process.create(:command_line => ssh_cmd,
:creation_flags => Process::DETACHED_PROCESS,
:process_inherit => false,
:thread_inherit => true,
:startup_info => {:stdin => w1, :stdout => r2, :stderr => f2})
else
p1 = spawn(sftp_server_cmd, :out => w2, :in => r1, :err => f1, :pgroup => true, :close_others => true)
p2 = spawn(ssh_cmd, :out => w1, :in => r2, :err => f2, :pgroup => true, :close_others => true)
# Detach from the processes so they will keep running
Process.detach(p1)
Process.detach(p2)
end
# Check that the mount made it
mounted = false
for i in 0..6
machine.ui.info("Checking Mount..")
if self.sshfs_forward_is_folder_mounted(machine, opts)
mounted = true
break
end
sleep(2)
end
if !mounted
f1.rewind # Seek to beginning of the file
f2.rewind # Seek to beginning of the file
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSSlaveMountFailed
raise error_class, sftp_stderr: f1.read, ssh_stderr: f2.read
end
machine.ui.info("Folder Successfully Mounted!")
end
# Do a normal sshfs mount in which we will ssh into the guest
# and then execute the sshfs command to connect the the opts[:ssh_host]
# and mount a folder from opts[:ssh_host] into the guest.
def self.sshfs_normal_mount(machine, opts, hostpath, expanded_guest_path)
# SSH connection options
ssh_opts = opts[:ssh_opts]
ssh_opts_append = opts[:ssh_opts_append].to_s # provided by user
# SSHFS executable options
sshfs_opts = opts[:sshfs_opts]
sshfs_opts_append = opts[:sshfs_opts_append].to_s # provided by user
# Host/Port and Auth Information
username = opts[:ssh_username]
password = opts[:ssh_password]
host = opts[:ssh_host]
port = opts[:ssh_port]
# Add echo of password if password is being used
echopipe = ""
if password
echopipe = "echo '#{password}' | "
sshfs_opts+= '-o password_stdin '
end
# Log some information
machine.ui.info(I18n.t("vagrant.sshfs.actions.normal_mounting_folder",
user: username, host: host,
hostpath: hostpath, guestpath: expanded_guest_path))
# Build up the command and connect
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSNormalMountFailed
cmd = echopipe
cmd+= "sshfs -p #{port} "
cmd+= ssh_opts + ' ' + ssh_opts_append + ' '
cmd+= sshfs_opts + ' ' + sshfs_opts_append + ' '
cmd+= "#{username}@#{host}:'#{hostpath}' #{expanded_guest_path}"
retryable(on: error_class, tries: 3, sleep: 3) do
machine.communicate.sudo(
cmd, error_class: error_class, error_key: :normal_mount_failed)
end
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/linux/sshfs_get_absolute_path.rb 0000664 0000000 0000000 00000001341 14044051046 0024664 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestLinux
module Cap
class SSHFSGetAbsolutePath
def self.sshfs_get_absolute_path(machine, path)
abs_path = ""
machine.communicate.execute("readlink -f #{path}", sudo: true) do |type, data|
if type == :stdout
abs_path = data
end
end
if ! abs_path
# If no real absolute path was detected then error out
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSGetAbsolutePathFailed
raise error_class, path: path
end
# Chomp the string so that any trailing newlines are killed
return abs_path.chomp
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/redhat/ 0000775 0000000 0000000 00000000000 14044051046 0017551 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/redhat/sshfs_client.rb 0000664 0000000 0000000 00000003600 14044051046 0022561 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestRedHat
module Cap
class SSHFSClient
def self.sshfs_install(machine)
case machine.guest.capability("flavor")
when :rhel_8
# fuse-sshfs isn't in EPEL8 and how to get it from RHEL repos
# without having to have the system subscribed is unclear:
# https://github.com/dustymabe/vagrant-sshfs/issues/108#issuecomment-601061947
# Using fuse-sshfs from EPEL7 works for now so let's just go with it.
# Do the install in such a way that the epel7 repo doesn't hang around
# on the system, which may have unintended consequences on RHEL8.
machine.communicate.sudo("rpm --import https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7")
machine.communicate.sudo("yum -y install fuse-sshfs --repofrompath=epel7,'http://download.fedoraproject.org/pub/epel/7/$basearch'")
when :rhel_7, :rhel # rhel7 and rhel6
# Install fuse-sshfs from epel
if !epel_installed(machine)
epel_install(machine)
end
machine.communicate.sudo("yum -y install fuse-sshfs")
end
end
def self.sshfs_installed(machine)
machine.communicate.test("rpm -q fuse-sshfs")
end
protected
def self.epel_installed(machine)
machine.communicate.test("rpm -q epel-release")
end
def self.epel_install(machine)
case machine.guest.capability("flavor")
when :rhel_7
machine.communicate.sudo("rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm")
when :rhel # rhel6
machine.communicate.sudo("rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm")
end
end
end
end
end
end
lib/vagrant-sshfs/cap/guest/suse/ 0000775 0000000 0000000 00000000000 14044051046 0017261 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/guest/suse/sshfs_client.rb 0000664 0000000 0000000 00000000510 14044051046 0022266 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module GuestSUSE
module Cap
class SSHFSClient
def self.sshfs_install(machine)
machine.communicate.sudo("zypper -n install sshfs")
end
def self.sshfs_installed(machine)
machine.communicate.test("rpm -q sshfs")
end
end
end
end
end
lib/vagrant-sshfs/cap/host/ 0000775 0000000 0000000 00000000000 14044051046 0016130 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/host/darwin/ 0000775 0000000 0000000 00000000000 14044051046 0017414 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/host/darwin/sshfs_reverse_mount.rb 0000664 0000000 0000000 00000016160 14044051046 0024050 0 ustar 00root root 0000000 0000000 require "log4r"
require "vagrant/util/retryable"
require "tempfile"
module VagrantPlugins
module HostDarwin
module Cap
class MountSSHFS
extend Vagrant::Util::Retryable
@@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs_reverse_mount")
def self.sshfs_reverse_is_folder_mounted(env, opts)
mounted = false
hostpath = opts[:hostpath].dup
hostpath.gsub!("'", "'\\\\''")
hostpath = hostpath.chomp('/') # remove trailing / if exists
hostpath = File.expand_path(hostpath) # get the absolute path of the file
mount_cmd = Vagrant::Util::Which.which('mount')
result = Vagrant::Util::Subprocess.execute(mount_cmd)
result.stdout.each_line do |line|
if line.split()[2] == hostpath
mounted = true
break
end
end
return mounted
end
def self.sshfs_reverse_mount_folder(env, machine, opts)
# opts contains something like:
# { :type=>:sshfs,
# :guestpath=>"/sharedfolder",
# :hostpath=>"/guests/sharedfolder",
# :disabled=>false
# :ssh_host=>"192.168.1.1"
# :ssh_port=>"22"
# :ssh_username=>"username"
# :ssh_password=>"password"
# }
self.sshfs_mount(machine, opts)
end
def self.sshfs_reverse_unmount_folder(env, machine, opts)
self.sshfs_unmount(machine, opts)
end
protected
# Perform a mount by running an sftp-server on the vagrant host
# and piping stdin/stdout to sshfs running inside the guest
def self.sshfs_mount(machine, opts)
sshfs_path = Vagrant::Util::Which.which('sshfs')
# expand the guest path so we can handle things like "~/vagrant"
expanded_guest_path = machine.guest.capability(
:shell_expand_guest_path, opts[:guestpath])
# Mount path information
hostpath = opts[:hostpath].dup
hostpath.gsub!("'", "'\\\\''")
# Add in some sshfs/fuse options that are common to both mount methods
opts[:sshfs_opts] = ' -o noauto_cache '# disable caching based on mtime
# Add in some ssh options that are common to both mount methods
opts[:ssh_opts] = ' -o StrictHostKeyChecking=no '# prevent yes/no question
opts[:ssh_opts]+= ' -o ServerAliveInterval=30 ' # send keepalives
# SSH connection options
# Note the backslash escapes for IdentityFile - handles spaces in key path
ssh_opts = opts[:ssh_opts]
ssh_opts+= ' -o Port=' + machine.ssh_info[:port].to_s
ssh_opts+= ' -o "IdentityFile=\"' + machine.ssh_info[:private_key_path][0] + '\""'
ssh_opts+= ' -o UserKnownHostsFile=/dev/null '
ssh_opts+= ' -F /dev/null ' # Don't pick up options from user's config
if machine.ssh_info.key?(:private_key_path) and
machine.ssh_info[:private_key_path] and
machine.ssh_info[:private_key_path][0]
# Add IdentityFile since there is one
# Note the backslash escapes for IdentityFile - handles spaces in key path
ssh_opts+= ' -o "IdentityFile=\"' + machine.ssh_info[:private_key_path][0] + '\""'
end
ssh_opts_append = opts[:ssh_opts_append].to_s # provided by user
# SSHFS executable options
sshfs_opts = opts[:sshfs_opts]
sshfs_opts_append = opts[:sshfs_opts_append].to_s # provided by user
username = machine.ssh_info[:username]
host = machine.ssh_info[:host]
# The sshfs command to mount the guest directory on the host
sshfs_cmd = "#{sshfs_path} #{ssh_opts} #{ssh_opts_append} "
sshfs_cmd+= "#{sshfs_opts} #{sshfs_opts_append} "
sshfs_cmd+= "#{username}@#{host}:#{expanded_guest_path} #{hostpath}"
# Log some information
@@logger.debug("sshfs cmd: #{sshfs_cmd}")
machine.ui.info(I18n.t("vagrant.sshfs.actions.reverse_mounting_folder",
hostpath: hostpath, guestpath: expanded_guest_path))
# Log STDERR to predictable files so that we can inspect them
# later in case things go wrong. We'll use the machines data
# directory (i.e. .vagrant/machines/default/virtualbox/) for this
f1path = machine.data_dir.join('vagrant_sshfs_sshfs_stderr.txt')
f1 = File.new(f1path, 'w+')
# Launch sshfs command to mount guest dir into the host
if Vagrant::Util::Platform.windows?
# Need to handle Windows differently. Kernel.spawn fails to work,
# if the shell creating the process is closed.
# See https://github.com/dustymabe/vagrant-sshfs/issues/31
Process.create(:command_line => ssh_cmd,
:creation_flags => Process::DETACHED_PROCESS,
:process_inherit => false,
:thread_inherit => true,
:startup_info => {:stdin => w2, :stdout => r1, :stderr => f1})
else
p1 = spawn(sshfs_cmd, :out => f1, :err => f1, :pgroup => true, :close_others => true)
Process.detach(p1) # Detach so process will keep running
end
# Check that the mount made it
mounted = false
for i in 0..6
machine.ui.info("Checking Mount..")
if self.sshfs_reverse_is_folder_mounted(machine, opts)
mounted = true
break
end
sleep(2)
end
if !mounted
f1.rewind # Seek to beginning of the file
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSReverseMountFailed
raise error_class, sshfs_output: f1.read
end
machine.ui.info("Folder Successfully Mounted!")
end
def self.sshfs_unmount(machine, opts)
# opts contains something like:
# { :type=>:sshfs,
# :guestpath=>"/sharedfolder",
# :hostpath=>"/guests/sharedfolder",
# :disabled=>false
# :ssh_host=>"192.168.1.1"
# :ssh_port=>"22"
# :ssh_username=>"username"
# :ssh_password=>"password"
# }
# Mount path information
hostpath = opts[:hostpath].dup
hostpath.gsub!("'", "'\\\\''")
# Log some information
machine.ui.info(I18n.t("vagrant.sshfs.actions.reverse_unmounting_folder",
hostpath: hostpath))
# Build up the command and connect
# on linux it is fusermount -u, on mac it is just umount
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSUnmountFailed
umount_cmd = Vagrant::Util::Which.which('umount')
cmd = "#{umount_cmd} #{hostpath}"
result = Vagrant::Util::Subprocess.execute(*cmd.split())
if result.exit_code != 0
raise error_class, command: cmd, stdout: result.stdout, stderr: result.stderr
end
end
end
end
end
end
lib/vagrant-sshfs/cap/host/linux/ 0000775 0000000 0000000 00000000000 14044051046 0017267 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/cap/host/linux/sshfs_reverse_mount.rb 0000664 0000000 0000000 00000015472 14044051046 0023730 0 ustar 00root root 0000000 0000000 require "log4r"
require "vagrant/util/retryable"
require "tempfile"
module VagrantPlugins
module HostLinux
module Cap
class MountSSHFS
extend Vagrant::Util::Retryable
@@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs_reverse_mount")
def self.sshfs_reverse_is_folder_mounted(env, opts)
mounted = false
hostpath = opts[:hostpath].dup
hostpath.gsub!("'", "'\\\\''")
hostpath = hostpath.chomp('/') # remove trailing / if exists
hostpath = File.expand_path(hostpath) # get the absolute path of the file
mounts = File.open('/proc/mounts', 'r')
mounts.each_line do |line|
if line.split()[1] == hostpath
mounted = true
break
end
end
return mounted
end
def self.sshfs_reverse_mount_folder(env, machine, opts)
# opts contains something like:
# { :type=>:sshfs,
# :guestpath=>"/sharedfolder",
# :hostpath=>"/guests/sharedfolder",
# :disabled=>false
# :ssh_host=>"192.168.1.1"
# :ssh_port=>"22"
# :ssh_username=>"username"
# :ssh_password=>"password"
# }
self.sshfs_mount(machine, opts)
end
def self.sshfs_reverse_unmount_folder(env, machine, opts)
self.sshfs_unmount(machine, opts)
end
protected
# Perform a mount by running an sftp-server on the vagrant host
# and piping stdin/stdout to sshfs running inside the guest
def self.sshfs_mount(machine, opts)
sshfs_path = Vagrant::Util::Which.which('sshfs')
# expand the guest path so we can handle things like "~/vagrant"
expanded_guest_path = machine.guest.capability(
:shell_expand_guest_path, opts[:guestpath])
# Mount path information
hostpath = opts[:hostpath].dup
hostpath.gsub!("'", "'\\\\''")
# Add in some sshfs/fuse options that are common to both mount methods
opts[:sshfs_opts] = ' -o noauto_cache '# disable caching based on mtime
# Add in some ssh options that are common to both mount methods
opts[:ssh_opts] = ' -o StrictHostKeyChecking=no '# prevent yes/no question
opts[:ssh_opts]+= ' -o ServerAliveInterval=30 ' # send keepalives
# SSH connection options
ssh_opts = opts[:ssh_opts]
ssh_opts+= ' -o Port=' + machine.ssh_info[:port].to_s
ssh_opts+= ' -o UserKnownHostsFile=/dev/null '
ssh_opts+= ' -F /dev/null ' # Don't pick up options from user's config
if machine.ssh_info.key?(:private_key_path) and
machine.ssh_info[:private_key_path] and
machine.ssh_info[:private_key_path][0]
# Add IdentityFile since there is one
# Note the backslash escapes for IdentityFile - handles spaces in key path
ssh_opts+= ' -o "IdentityFile=\"' + machine.ssh_info[:private_key_path][0] + '\""'
end
ssh_opts_append = opts[:ssh_opts_append].to_s # provided by user
# SSHFS executable options
sshfs_opts = opts[:sshfs_opts]
sshfs_opts_append = opts[:sshfs_opts_append].to_s # provided by user
username = machine.ssh_info[:username]
host = machine.ssh_info[:host]
# The sshfs command to mount the guest directory on the host
sshfs_cmd = "#{sshfs_path} #{ssh_opts} #{ssh_opts_append} "
sshfs_cmd+= "#{sshfs_opts} #{sshfs_opts_append} "
sshfs_cmd+= "#{username}@#{host}:#{expanded_guest_path} #{hostpath}"
# Log some information
@@logger.debug("sshfs cmd: #{sshfs_cmd}")
machine.ui.info(I18n.t("vagrant.sshfs.actions.reverse_mounting_folder",
hostpath: hostpath, guestpath: expanded_guest_path))
# Log STDERR to predictable files so that we can inspect them
# later in case things go wrong. We'll use the machines data
# directory (i.e. .vagrant/machines/default/virtualbox/) for this
f1path = machine.data_dir.join('vagrant_sshfs_sshfs_stderr.txt')
f1 = File.new(f1path, 'w+')
# Launch sshfs command to mount guest dir into the host
if Vagrant::Util::Platform.windows?
# Need to handle Windows differently. Kernel.spawn fails to work,
# if the shell creating the process is closed.
# See https://github.com/dustymabe/vagrant-sshfs/issues/31
Process.create(:command_line => ssh_cmd,
:creation_flags => Process::DETACHED_PROCESS,
:process_inherit => false,
:thread_inherit => true,
:startup_info => {:stdin => w2, :stdout => r1, :stderr => f1})
else
p1 = spawn(sshfs_cmd, :out => f1, :err => f1, :pgroup => true, :close_others => true)
Process.detach(p1) # Detach so process will keep running
end
# Check that the mount made it
mounted = false
for i in 0..6
machine.ui.info("Checking Mount..")
if self.sshfs_reverse_is_folder_mounted(machine, opts)
mounted = true
break
end
sleep(2)
end
if !mounted
f1.rewind # Seek to beginning of the file
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSReverseMountFailed
raise error_class, sshfs_output: f1.read
end
machine.ui.info("Folder Successfully Mounted!")
end
def self.sshfs_unmount(machine, opts)
# opts contains something like:
# { :type=>:sshfs,
# :guestpath=>"/sharedfolder",
# :hostpath=>"/guests/sharedfolder",
# :disabled=>false
# :ssh_host=>"192.168.1.1"
# :ssh_port=>"22"
# :ssh_username=>"username"
# :ssh_password=>"password"
# }
# Mount path information
hostpath = opts[:hostpath].dup
hostpath.gsub!("'", "'\\\\''")
# Log some information
machine.ui.info(I18n.t("vagrant.sshfs.actions.reverse_unmounting_folder",
hostpath: hostpath))
# Build up the command and connect
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSUnmountFailed
fusermount_cmd = Vagrant::Util::Which.which('fusermount')
cmd = "#{fusermount_cmd} -u #{hostpath}"
result = Vagrant::Util::Subprocess.execute(*cmd.split())
if result.exit_code != 0
raise error_class, command: cmd, stdout: result.stdout, stderr: result.stderr
end
end
end
end
end
end
lib/vagrant-sshfs/command.rb 0000664 0000000 0000000 00000003535 14044051046 0016361 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module SyncedFolderSSHFS
module Command
class SSHFS < Vagrant.plugin("2", :command)
include Vagrant::Action::Builtin::MixinSyncedFolders
def self.synopsis
"mounts SSHFS shared folder mounts into the remote machine"
end
def execute
options = {:unmount => false} # Default to mounting shares
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant sshfs [--mount|--unmount] [vm-name]"
o.separator ""
o.separator "Mount or unmount sshfs synced folders into the vagrant box"
o.separator ""
o.on("--mount", "Mount folders - the default") do
options[:unmount] = false
end
o.on("--unmount", "Unmount folders") do
options[:unmount] = true
end
end
# Parse the options and return if we don't have any target.
argv = parse_options(opts)
return if !argv
# Go through each machine and perform the rsync
error = false
with_target_vms(argv) do |machine|
# Is the machine up yet?
if !machine.communicate.ready?
machine.ui.error(I18n.t("vagrant.sshfs.errors.communicator_not_ready"))
error = true
next
end
# Determine the sshfs synced folders for this machine
folders = synced_folders(machine, cached: false)[:sshfs]
next if !folders || folders.empty?
# Mount or Unmount depending on the user's request
if options[:unmount]
SyncedFolder.new.disable(machine, folders, {})
else
SyncedFolder.new.enable(machine, folders, {})
end
end
return error ? 1 : 0
end
end
end
end
end
lib/vagrant-sshfs/errors.rb 0000664 0000000 0000000 00000002004 14044051046 0016245 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module SyncedFolderSSHFS
module Errors
# A convenient superclass for all our errors.
class SSHFSError < Vagrant::Errors::VagrantError
error_namespace("vagrant.sshfs.errors")
end
class SSHFSNormalMountFailed < SSHFSError
error_key(:normal_mount_failed)
end
class SSHFSSlaveMountFailed < SSHFSError
error_key(:slave_mount_failed)
end
class SSHFSReverseMountFailed < SSHFSError
error_key(:reverse_mount_failed)
end
class SSHFSUnmountFailed < SSHFSError
error_key(:unmount_failed)
end
class SSHFSInstallFailed < SSHFSError
error_key(:install_failed)
end
class SSHFSNotInstalledInGuest < SSHFSError
error_key(:sshfs_not_in_guest)
end
class SSHFSExeNotAvailable < SSHFSError
error_key(:exe_not_in_host)
end
class SSHFSGetAbsolutePathFailed < SSHFSError
error_key(:get_absolute_path_failed)
end
end
end
end
lib/vagrant-sshfs/plugin.rb 0000664 0000000 0000000 00000015105 14044051046 0016235 0 ustar 00root root 0000000 0000000 require "vagrant"
module VagrantPlugins
module SyncedFolderSSHFS
# This plugin implements SSHFS synced folders.
class Plugin < Vagrant.plugin("2")
name "SSHFS synced folders"
description <<-EOF
The SSHFS synced folders plugin enables you to use SSHFS as a synced folder
implementation.
EOF
synced_folder("sshfs", 5) do
require_relative "synced_folder"
SyncedFolder
end
command("sshfs", primary: true) do
require_relative "command"
Command::SSHFS
end
# The following two hooks allow us to workaround
# the config validations that assume the hostpaths
# are coming from our host machine. This is not the
# case for arbitrary host mounts.
action_hook("sshfs_hostpath_fixup") do |hook|
require_relative "action_hostpath_fixup"
hook.before(
Vagrant::Action::Builtin::ConfigValidate,
HostPathFix)
end
action_hook("sshfs_hostpath_unfix") do |hook|
require_relative "action_hostpath_fixup"
hook.after(
Vagrant::Action::Builtin::ConfigValidate,
HostPathUnfix)
end
host_capability("linux", "sshfs_reverse_mount_folder") do
require_relative "cap/host/linux/sshfs_reverse_mount"
VagrantPlugins::HostLinux::Cap::MountSSHFS
end
host_capability("linux", "sshfs_reverse_unmount_folder") do
require_relative "cap/host/linux/sshfs_reverse_mount"
VagrantPlugins::HostLinux::Cap::MountSSHFS
end
host_capability("linux", "sshfs_reverse_is_folder_mounted") do
require_relative "cap/host/linux/sshfs_reverse_mount"
VagrantPlugins::HostLinux::Cap::MountSSHFS
end
host_capability("darwin", "sshfs_reverse_mount_folder") do
require_relative "cap/host/darwin/sshfs_reverse_mount"
VagrantPlugins::HostDarwin::Cap::MountSSHFS
end
host_capability("darwin", "sshfs_reverse_unmount_folder") do
require_relative "cap/host/darwin/sshfs_reverse_mount"
VagrantPlugins::HostDarwin::Cap::MountSSHFS
end
host_capability("darwin", "sshfs_reverse_is_folder_mounted") do
require_relative "cap/host/darwin/sshfs_reverse_mount"
VagrantPlugins::HostDarwin::Cap::MountSSHFS
end
guest_capability("linux", "sshfs_forward_mount_folder") do
require_relative "cap/guest/linux/sshfs_forward_mount"
VagrantPlugins::GuestLinux::Cap::MountSSHFS
end
guest_capability("linux", "sshfs_forward_unmount_folder") do
require_relative "cap/guest/linux/sshfs_forward_mount"
VagrantPlugins::GuestLinux::Cap::MountSSHFS
end
guest_capability("linux", "sshfs_forward_is_folder_mounted") do
require_relative "cap/guest/linux/sshfs_forward_mount"
VagrantPlugins::GuestLinux::Cap::MountSSHFS
end
guest_capability("linux", "sshfs_get_absolute_path") do
require_relative "cap/guest/linux/sshfs_get_absolute_path"
VagrantPlugins::GuestLinux::Cap::SSHFSGetAbsolutePath
end
guest_capability("redhat", "sshfs_installed") do
require_relative "cap/guest/redhat/sshfs_client"
VagrantPlugins::GuestRedHat::Cap::SSHFSClient
end
guest_capability("redhat", "sshfs_install") do
require_relative "cap/guest/redhat/sshfs_client"
VagrantPlugins::GuestRedHat::Cap::SSHFSClient
end
guest_capability("centos", "sshfs_installed") do
require_relative "cap/guest/centos/sshfs_client"
VagrantPlugins::GuestCentOS::Cap::SSHFSClient
end
guest_capability("centos", "sshfs_install") do
require_relative "cap/guest/centos/sshfs_client"
VagrantPlugins::GuestCentOS::Cap::SSHFSClient
end
guest_capability("fedora", "sshfs_installed") do
require_relative "cap/guest/fedora/sshfs_client"
VagrantPlugins::GuestFedora::Cap::SSHFSClient
end
guest_capability("fedora", "sshfs_install") do
require_relative "cap/guest/fedora/sshfs_client"
VagrantPlugins::GuestFedora::Cap::SSHFSClient
end
guest_capability("debian", "sshfs_installed") do
require_relative "cap/guest/debian/sshfs_client"
VagrantPlugins::GuestDebian::Cap::SSHFSClient
end
guest_capability("debian", "sshfs_install") do
require_relative "cap/guest/debian/sshfs_client"
VagrantPlugins::GuestDebian::Cap::SSHFSClient
end
guest_capability("arch", "sshfs_installed") do
require_relative "cap/guest/arch/sshfs_client"
VagrantPlugins::GuestArch::Cap::SSHFSClient
end
guest_capability("arch", "sshfs_install") do
require_relative "cap/guest/arch/sshfs_client"
VagrantPlugins::GuestArch::Cap::SSHFSClient
end
guest_capability("alpine", "sshfs_installed") do
require_relative "cap/guest/alpine/sshfs_client"
VagrantPlugins::GuestAlpine::Cap::SSHFSClient
end
guest_capability("alpine", "sshfs_install") do
require_relative "cap/guest/alpine/sshfs_client"
VagrantPlugins::GuestAlpine::Cap::SSHFSClient
end
guest_capability("suse", "sshfs_installed") do
require_relative "cap/guest/suse/sshfs_client"
VagrantPlugins::GuestSUSE::Cap::SSHFSClient
end
guest_capability("suse", "sshfs_install") do
require_relative "cap/guest/suse/sshfs_client"
VagrantPlugins::GuestSUSE::Cap::SSHFSClient
end
guest_capability("freebsd", "sshfs_forward_mount_folder") do
require_relative "cap/guest/freebsd/sshfs_forward_mount"
VagrantPlugins::GuestFreeBSD::Cap::MountSSHFS
end
guest_capability("freebsd", "sshfs_forward_unmount_folder") do
require_relative "cap/guest/freebsd/sshfs_forward_mount"
VagrantPlugins::GuestFreeBSD::Cap::MountSSHFS
end
guest_capability("freebsd", "sshfs_forward_is_folder_mounted") do
require_relative "cap/guest/freebsd/sshfs_forward_mount"
VagrantPlugins::GuestFreeBSD::Cap::MountSSHFS
end
guest_capability("freebsd", "sshfs_get_absolute_path") do
require_relative "cap/guest/linux/sshfs_get_absolute_path"
VagrantPlugins::GuestLinux::Cap::SSHFSGetAbsolutePath
end
guest_capability("freebsd", "sshfs_install") do
require_relative "cap/guest/freebsd/sshfs_client"
VagrantPlugins::GuestFreeBSD::Cap::SSHFSClient
end
guest_capability("freebsd", "sshfs_installed") do
require_relative "cap/guest/freebsd/sshfs_client"
VagrantPlugins::GuestFreeBSD::Cap::SSHFSClient
end
end
end
end
lib/vagrant-sshfs/synced_folder.rb 0000664 0000000 0000000 00000010651 14044051046 0017560 0 ustar 00root root 0000000 0000000 require "log4r"
require "vagrant/util/platform"
require "vagrant/util/which"
require_relative "synced_folder/sshfs_forward_mount"
require_relative "synced_folder/sshfs_reverse_mount"
module VagrantPlugins
module SyncedFolderSSHFS
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
def initialize(*args)
super
@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs")
end
# This is called early when the synced folder is set to determine
# if this implementation can be used for this machine. This should
# return true or false.
#
# @param [Machine] machine
# @param [Boolean] raise_error If true, should raise an exception
# if it isn't usable.
# @return [Boolean]
def usable?(machine, raise_error=false)
return true #for now
end
# This is called after the machine is booted and after networks
# are setup.
#
# This might be called with new folders while the machine is running.
# If so, then this should add only those folders without removing
# any existing ones.
#
# No return value.
def enable(machine, folders, pluginopts)
# Iterate through the folders and mount if needed
folders.each do |id, opts|
if opts.has_key?(:reverse) and opts[:reverse]
do_reverse_mount(machine, opts)
else
do_forward_mount(machine, opts)
end
end
end
# This is called to remove the synced folders from a running
# machine.
#
# This is not guaranteed to be called, but this should be implemented
# by every synced folder implementation.
#
# @param [Machine] machine The machine to modify.
# @param [Hash] folders The folders to remove. This will not contain
# any folders that should remain.
# @param [Hash] opts Any options for the synced folders.
def disable(machine, folders, opts)
# Iterate through the folders and mount if needed
folders.each do |id, opts|
if opts.has_key?(:reverse) and opts[:reverse]
do_reverse_unmount(machine, opts)
else
do_forward_unmount(machine, opts)
end
end
end
# This is called after destroying the machine during a
# `vagrant destroy` and also prior to syncing folders during
# a `vagrant up`.
#
# No return value.
#
# @param [Machine] machine
# @param [Hash] opts
def cleanup(machine, opts)
end
protected
# Function to find the path to an executable with name "name"
def find_executable(name)
error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSExeNotAvailable
# Save off PATH env var before we modify it
oldpath = ENV['PATH']
# Try to include paths where sftp-server may live so
# That we have a good chance of finding it
if Vagrant::Util::Platform.windows?
if Vagrant::Util::Platform.cygwin?
# If in a cygwin terminal then we can programmatically
# determine where sftp-server would be. ssh should already
# be in path.
cygwin_root = Vagrant::Util::Platform.cygwin_windows_path('/')
ENV['PATH'] += ';' + cygwin_root + '\usr\sbin'
else
# If not in a cygwin terminal then we'll have to guess
# where cygwin is installed and add the /bin/ (for ssh) and
# /usr/sbin (for sftp-server) to the PATH.
ENV['PATH'] += ';C:\cygwin\bin'
ENV['PATH'] += ';C:\cygwin\usr\sbin'
ENV['PATH'] += ';C:\cygwin64\bin'
ENV['PATH'] += ';C:\cygwin64\usr\sbin'
end
else
ENV['PATH'] += ':/usr/libexec/ssh' # Linux (openSUSE/SUSE Family)
ENV['PATH'] += ':/usr/libexec/openssh' # Linux (Red Hat Family)
ENV['PATH'] += ':/usr/lib/openssh' # Linux (Debian Family)
ENV['PATH'] += ':/usr/lib/ssh' # Linux (Arch Linux Family)
ENV['PATH'] += ':/usr/lib64/misc' # Linux (Gentoo Family)
ENV['PATH'] += ':/usr/libexec/' # Mac OS X
end
# Try to find the executable
exepath = Vagrant::Util::Which.which(name)
raise error_class, executable: name if !exepath
# Restore the PATH variable and return
ENV['PATH'] = oldpath
return exepath
end
end
end
end
lib/vagrant-sshfs/synced_folder/ 0000775 0000000 0000000 00000000000 14044051046 0017230 5 ustar 00root root 0000000 0000000 lib/vagrant-sshfs/synced_folder/sshfs_forward_mount.rb 0000664 0000000 0000000 00000010303 14044051046 0023646 0 ustar 00root root 0000000 0000000 require "log4r"
require "vagrant/util/platform"
require "vagrant/util/which"
module VagrantPlugins
module SyncedFolderSSHFS
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
protected
# Do a forward mount: mounting host folder into the guest
def do_forward_mount(machine, opts)
# Check to see if sshfs software is in the guest
if machine.guest.capability?(:sshfs_installed)
if !machine.guest.capability(:sshfs_installed)
can_install = machine.guest.capability?(:sshfs_install)
if !can_install
raise VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSNotInstalledInGuest
end
machine.ui.info(I18n.t("vagrant.sshfs.actions.installing"))
machine.guest.capability(:sshfs_install)
end
end
# If already mounted then there is nothing to do
if machine.guest.capability(:sshfs_forward_is_folder_mounted, opts)
machine.ui.info(
I18n.t("vagrant.sshfs.info.already_mounted",
location: 'guest', folder: opts[:guestpath]))
return
end
# If the synced folder entry has host information in it then
# assume we are doing a normal sshfs mount to a host that isn't
# the machine running vagrant. Rely on password/ssh keys.
#
# If not, then we are doing a slave mount and we need to
# make sure we can find the sftp-server and ssh execuatable
# files on the host.
if opts.has_key?(:ssh_host) and opts[:ssh_host]
# Check port information and find out auth info
check_host_port(machine, opts)
get_auth_info(machine, opts)
else
opts[:ssh_exe_path] = find_executable('ssh')
opts[:sftp_server_exe_path] = find_executable('sftp-server')
end
# Do the mount
machine.ui.info(I18n.t("vagrant.sshfs.actions.mounting"))
machine.guest.capability(:sshfs_forward_mount_folder, opts)
end
def do_forward_unmount(machine, opts)
# If not mounted then there is nothing to do
if ! machine.guest.capability(:sshfs_forward_is_folder_mounted, opts)
machine.ui.info(
I18n.t("vagrant.sshfs.info.not_mounted",
location: 'guest', folder: opts[:guestpath]))
return
end
# Do the Unmount
machine.ui.info(I18n.t("vagrant.sshfs.actions.unmounting"))
machine.guest.capability(:sshfs_forward_unmount_folder, opts)
end
# Check if port information was provided in the options. If not,
# then default to port 22 for ssh
def check_host_port(machine, opts)
if not opts.has_key?(:ssh_port) or not opts[:ssh_port]
opts[:ssh_port] = '22'
end
end
# Function to gather authentication information (username/password)
# for doing a normal sshfs mount
def get_auth_info(machine, opts)
prompt_for_password = false
ssh_info = machine.ssh_info
# Detect the username of the current user
username = `whoami`.strip
# If no username provided then default to the current
# user that is executing vagrant
if not opts.has_key?(:ssh_username) or not opts[:ssh_username]
opts[:ssh_username] = username
end
# Check to see if we need to prompt the user for a password.
# We will prompt if:
# - User asked us to via prompt_for_password option
# - User did not provide a password in options and is not fwding ssh agent
#
if opts.has_key?(:prompt_for_password) and opts[:prompt_for_password]
prompt_for_password = opts[:prompt_for_password]
end
if not opts.has_key?(:ssh_password) or not opts[:ssh_password]
if not ssh_info.has_key?(:forward_agent) or not ssh_info[:forward_agent]
prompt_for_password = true
end
end
# Now do the prompt
if prompt_for_password
opts[:ssh_password] = machine.ui.ask(
I18n.t("vagrant.sshfs.ask.prompt_for_password", username: opts[:ssh_username]),
echo: false)
end
end
end
end
end
lib/vagrant-sshfs/synced_folder/sshfs_reverse_mount.rb 0000664 0000000 0000000 00000003160 14044051046 0023660 0 ustar 00root root 0000000 0000000 require "log4r"
require "vagrant/util/platform"
require "vagrant/util/which"
module VagrantPlugins
module SyncedFolderSSHFS
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
protected
# Do a reverse mount: mounting guest folder onto the host
def do_reverse_mount(machine, opts)
# Check to see if sshfs software is in the host
if machine.env.host.capability?(:sshfs_installed)
if !machine.env.host.capability(:sshfs_installed)
raise VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSNotInstalledInHost
end
end
# If already mounted then there is nothing to do
if machine.env.host.capability(:sshfs_reverse_is_folder_mounted, opts)
machine.ui.info(
I18n.t("vagrant.sshfs.info.already_mounted",
location: 'host', folder: opts[:hostpath]))
return
end
# Do the mount
machine.ui.info(I18n.t("vagrant.sshfs.actions.mounting"))
machine.env.host.capability(:sshfs_reverse_mount_folder, machine, opts)
end
def do_reverse_unmount(machine, opts)
# If not mounted then there is nothing to do
if ! machine.env.host.capability(:sshfs_reverse_is_folder_mounted, opts)
machine.ui.info(
I18n.t("vagrant.sshfs.info.not_mounted",
location: 'host', folder: opts[:hostpath]))
return
end
# Do the Unmount
machine.ui.info(I18n.t("vagrant.sshfs.actions.unmounting"))
machine.env.host.capability(:sshfs_reverse_unmount_folder, machine, opts)
end
end
end
end
lib/vagrant-sshfs/version.rb 0000664 0000000 0000000 00000000121 14044051046 0016414 0 ustar 00root root 0000000 0000000 module VagrantPlugins
module SyncedFolderSSHFS
VERSION = "1.3.6"
end
end
locales/ 0000775 0000000 0000000 00000000000 14044051046 0012476 5 ustar 00root root 0000000 0000000 locales/synced_folder_sshfs.yml 0000664 0000000 0000000 00000006671 14044051046 0017261 0 ustar 00root root 0000000 0000000 en:
vagrant:
sshfs:
actions:
installing: Installing SSHFS client...
mounting: Mounting SSHFS shared folder...
unmounting: Unmounting SSHFS shared folder...
unmounting_folder: |-
Unmounting SSHFS shared folder mounted at %{guestpath}
reverse_unmounting_folder: |-
Unmounting SSHFS shared folder mounted at host's %{hostpath}
reverse_mounting_folder: |-
mounting folder via SSHFS: guestpath:%{guestpath} => hostpath:%{hostpath}
slave_mounting_folder: |-
Mounting folder via SSHFS: %{hostpath} => %{guestpath}
normal_mounting_folder: |-
Mounting folder via SSHFS: %{user}@%{host}:%{hostpath} => %{guestpath}
ask:
prompt_for_password: |-
SSHFS password for '%{username}':
info:
detected_host_ip: |-
Detected host IP address is '%{ip}'
already_mounted: |-
The folder %{folder} in the %{location} is already mounted.
not_mounted: |-
The folder %{folder} in the %{location} is not mounted.
errors:
communicator_not_ready: |-
The machine is reporting that it is not ready to communicate via ssh. Verify
this machine is properly running.
exe_not_in_host: |-
The '%{executable}' executable file can't be found on the host machine but
is required for sshfs mounting to work. Please install the software and
try again.
sshfs_not_in_guest: |-
The necessary SSHFS software is not installed in the guest.
get_absolute_path_failed: |-
Could not get the absolute path of the folder within the guest '%{path}'
install_failed_arch: |-
The install of the sshfs client software failed. On Arch this is most likely
because the package lists are not up to date [1] and partial upgrades are not
supported [2]. Please update your Arch system or install SSHFS manually.
[1] https://wiki.archlinux.org/index.php/pacman#Packages_cannot_be_retrieved_on_installation
[2] https://wiki.archlinux.org/index.php/System_maintenance#Partial_upgrades_are_unsupported
normal_mount_failed: |-
Mounting SSHFS shared folders failed. This is most often caused by either an
SSH Daemon not running on the target host or invalid credentials being provided.
Please make sure an SSH daemon is running on the host and proper credentials
were provided to be able to authenticate via SSH.
The command and output are:
%{command}
Stdout from the command:
%{stdout}
Stderr from the command:
%{stderr}
reverse_mount_failed: |-
Mounting SSHFS shared folder via reverse SSHFS mount failed. Please
look at the below output from from the processes that were run.
SSHFS command output:
%{sshfs_output}
slave_mount_failed: |-
Mounting SSHFS shared folder via slave SSHFS mount failed. Please
look at the below STDERR output from the processes that were run.
SSH command:
%{ssh_stderr}
SFTP command:
%{sftp_stderr}
unmount_failed: |-
Unmount the SSHFS mount failed.
The command and output are:
%{command}
Stdout from the command:
%{stdout}
Stderr from the command:
%{stderr}
test/ 0000775 0000000 0000000 00000000000 14044051046 0012033 5 ustar 00root root 0000000 0000000 test/misc/ 0000775 0000000 0000000 00000000000 14044051046 0012766 5 ustar 00root root 0000000 0000000 test/misc/README.txt 0000664 0000000 0000000 00000003457 14044051046 0014475 0 ustar 00root root 0000000 0000000
# This directory is for testing the three different mount modes
# that are supported by vagrant-sshfs
# To test we will first create the directory on the machine where
# we will mount the guest /etc/ into the host (the reverse mount).
mkdir /tmp/reverse_mount_etc
# Next we will define where our 3rd party host is (the normal mount).
# This can be another vagrant box or whatever machine you want.
export THIRD_PARTY_HOST='192.168.121.73'
export THIRD_PARTY_HOST_USER='vagrant'
export THIRD_PARTY_HOST_PASS='vagrant'
# Open an extra file descriptor to test it is not passed onto child processes
# https://github.com/dustymabe/vagrant-sshfs/issues/120
tmpfile=$(mktemp)
exec {extra_fd}<> "$tmpfile"
# Next vagrant up - will do 4 mounts
# - slave
# - slave with sym link
# - normal
# - reverse
vagrant up
# Next run the script to test the mounts:
$ bash dotests.sh
Testing slave forward mount!
d635332fe7aa4d4fb48e5cb9357bdedf
Testing slave forward mount with a symlink!
d635332fe7aa4d4fb48e5cb9357bdedf
Testing normal forward mount!
6ccc3034df924bd289dd16205bf3d629
Testing reverse mount!
508619e7e68e446c84d1fcdf7e0dc577
# We are printing out the machine-id under each mount. The first two
should be the same, because they are from the same machine. The last
two should be different.
# Close our file descriptor. No other process should be using it
exec {extra_fd}>&-
if lsof -wn -d $extra_fd | grep "$tmpfile"; then
echo "Failure: there are processes running that hold an inherited file descriptor"
fi
test/misc/Vagrantfile 0000664 0000000 0000000 00000002171 14044051046 0015154 0 ustar 00root root 0000000 0000000 Vagrant.configure(2) do |config|
config.ssh.insert_key = 'true'
# Test a forward slave mount:
# mounting /etc/ from the vagrant host into the guest
config.vm.synced_folder "/etc/", "/tmp/forward_slave_mount_etc/", type: "sshfs"
# Test a forward mount to a location that is a symbolic link
# https://github.com/dustymabe/vagrant-sshfs/issues/44
config.vm.synced_folder "/etc/", "/var/run/forward_slave_mount_sym_link_test/", type: "sshfs"
# Test a forward normal mount:
# mounting a folder from a 3rd party host into guest
config.vm.synced_folder "/etc/", "/tmp/forward_normal_mount_etc/", type: "sshfs",
ssh_host: ENV['THIRD_PARTY_HOST'],
ssh_username: ENV['THIRD_PARTY_HOST_USER'],
ssh_password: ENV['THIRD_PARTY_HOST_PASS']
# Test a reverse mount:
# mounting /etc/ from vagrant guest into vagrant host
config.vm.synced_folder "/tmp/reverse_mount_etc/", "/etc", type: "sshfs", reverse: true
host = 'sshfs-tests'
box = 'fedora/34-cloud-base'
config.vm.define host do | tmp |
tmp.vm.hostname = host
tmp.vm.box = box
end
end
test/misc/dotests.sh 0000664 0000000 0000000 00000001020 14044051046 0015000 0 ustar 00root root 0000000 0000000 #!/bin/bash
set -eu
# Test the four mounts we have done
echo -en "Testing slave forward mount!\n\t"
vagrant ssh -- cat /tmp/forward_slave_mount_etc/machine-id
# https://github.com/dustymabe/vagrant-sshfs/issues/44
echo -en "Testing slave forward mount with a symlink!\n\t"
vagrant ssh -- cat /run/forward_slave_mount_sym_link_test/machine-id
echo -en "Testing normal forward mount!\n\t"
vagrant ssh -- cat /tmp/forward_normal_mount_etc/machine-id
echo -en "Testing reverse mount!\n\t"
cat /tmp/reverse_mount_etc/machine-id
vagrant-sshfs.gemspec 0000664 0000000 0000000 00000002060 14044051046 0015205 0 ustar 00root root 0000000 0000000 # coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'vagrant-sshfs/version'
Gem::Specification.new do |spec|
spec.name = "vagrant-sshfs"
spec.version = VagrantPlugins::SyncedFolderSSHFS::VERSION
spec.authors = ["Dusty Mabe"]
spec.email = ["dusty@dustymabe.com"]
spec.description = """
A Vagrant synced folder plugin that mounts folders via SSHFS.
This is the successor to Fabio Kreusch's implementation:
https://github.com/fabiokr/vagrant-sshfs"""
spec.summary = spec.description
spec.homepage = "https://github.com/dustymabe/vagrant-sshfs"
spec.license = "GPL-2.0"
spec.files = `git ls-files -z`.split("\x0")
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency 'win32-process'
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'rake'
end