pax_global_header00006660000000000000000000000064132775607100014522gustar00rootroot0000000000000052 comment=93b672d82940e2e0dcc44bdd99429a83bd89155f vagrant-hostmanager-1.8.9/000077500000000000000000000000001327756071000155115ustar00rootroot00000000000000vagrant-hostmanager-1.8.9/.gitignore000066400000000000000000000000451327756071000175000ustar00rootroot00000000000000*.gem pkg Gemfile.lock test/.vagrant vagrant-hostmanager-1.8.9/CHANGELOG.md000066400000000000000000000067721327756071000173360ustar00rootroot00000000000000# Changelog ## 1.6.1 ### Bug fixes * Retain tmp hosts file and fix a bug where powershell mv does not move folder contents, in that context it's moving a file. [[#157](https://github.com/smdahlen/vagrant-hostmanager/issues/157)] [Full diff](https://github.com/smdahlen/vagrant-hostmanager/compare/v1.6.0...v1.6.1) ## 1.6.0 ### Features * splits hostnames across many lines [[#67](https://github.com/smdahlen/vagrant-hostmanager/pull/103)] ### Bug fixes * show description for hostmanager when vagrant list-commands is triggered [[#105](https://github.com/smdahlen/vagrant-hostmanager/pull/105)] ### Miscelaneous * extract old vagrant version compatibility code into util method [[#97](https://github.com/smdahlen/vagrant-hostmanager/pull/97)] * migrate HostsFile code into its own class [[#98](https://github.com/smdahlen/vagrant-hostmanager/pull/97)] [Full diff](https://github.com/smdahlen/vagrant-hostmanager/compare/v1.5.0...v1.6.0) ## 1.5.0 ### Features * hostmanager now runs *before* provisioning takes place, on `up` action [[#73](https://github.com/smdahlen/vagrant-hostmanager/issues/73)] ### Bug fixes * properly detect hosts file location on Windows guests [[#67](https://github.com/smdahlen/vagrant-hostmanager/pull/67)] * do not add host if IP cannot be determined [[#85](https://github.com/smdahlen/vagrant-hostmanager/pull/85)] * force moving of hosts file on Linux guests [[#93](https://github.com/smdahlen/vagrant-hostmanager/pull/93)] * allow top-level config options (eg. `ip_resolver`) to propagate to machine configs [[#91](https://github.com/smdahlen/vagrant-hostmanager/issues/91)] ### Miscelaneous * add passwordless sudo instructions to README [[#95](https://github.com/smdahlen/vagrant-hostmanager/pull/95)] [Full diff](https://github.com/smdahlen/vagrant-hostmanager/compare/v1.4.0...v1.5.0) ## 1.4.0 ### Features * supports vagrant 1.5 [[#80](https://github.com/smdahlen/vagrant-hostmanager/issues/80), [#81](https://github.com/smdahlen/vagrant-hostmanager/pull/81)] * only updates hosts file if contents have changed [[#78](https://github.com/smdahlen/vagrant-hostmanager/pull/78)] * custom ip resolver now has access to the machine whose hosts file is being updated [[#62](https://github.com/smdahlen/vagrant-hostmanager/pull/62)] ### Bug fixes * custom IP resolver result no longer ignored [[#57](https://github.com/smdahlen/vagrant-hostmanager/pull/57)] * when multiple private_networks are configured, the first one is used [[#64](https://github.com/smdahlen/vagrant-hostmanager/pull/64)] * destroyed machines are now removed from hosts file [[#52](https://github.com/smdahlen/vagrant-hostmanager/pull/52)] [Full diff](https://github.com/smdahlen/vagrant-hostmanager/compare/v1.3.0...v1.4.0) ## 1.3.0 ### Features * allow defining a custom IP resolver block [[#15](https://github.com/smdahlen/vagrant-hostmanager/pull/15)] * handle removing destroyed machines from hosts file (currently only works with `include_offline = true`) [[#45](https://github.com/smdahlen/vagrant-hostmanager/pull/45)] * attempt to elevate privileges when needed in Windows hosts [[#48](https://github.com/smdahlen/vagrant-hostmanager/pull/48)] ### Bug fixes * `--provider` command-line option now finds machines as expected [[#46](https://github.com/smdahlen/vagrant-hostmanager/pull/46)] * uses proper `hosts` file location in Windows under cygwin [[#49](https://github.com/smdahlen/vagrant-hostmanager/pull/49)] ### Miscelaneous * MIT license added to gemspec [Full diff](https://github.com/smdahlen/vagrant-hostmanager/compare/v1.2.3...v1.3.0) vagrant-hostmanager-1.8.9/Gemfile000066400000000000000000000002561327756071000170070ustar00rootroot00000000000000source 'https://rubygems.org' group :development do gem 'vagrant', :git => 'git://github.com/mitchellh/vagrant.git', :tag => 'v1.9.4' end group :plugins do gemspec end vagrant-hostmanager-1.8.9/LICENSE000066400000000000000000000405251327756071000165240ustar00rootroot00000000000000Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. vagrant-hostmanager-1.8.9/README.md000066400000000000000000000221171327756071000167730ustar00rootroot00000000000000Vagrant Host Manager ==================== [![Gem](https://img.shields.io/gem/v/vagrant-hostmanager.svg)](https://rubygems.org/gems/vagrant-hostmanager) [![Gem](https://img.shields.io/gem/dt/vagrant-hostmanager.svg)](https://rubygems.org/gems/vagrant-hostmanager) [![Gem](https://img.shields.io/gem/dtv/vagrant-hostmanager.svg)](https://rubygems.org/gems/vagrant-hostmanager) [![Twitter](https://img.shields.io/twitter/url/https/github.com/devopsgroup-io/vagrant-hostmanager.svg?style=social)](https://twitter.com/intent/tweet?text=Check%20out%20this%20awesome%20Vagrant%20plugin%21&url=https%3A%2F%2Fgithub.com%devopsgroup-io%2Fvagrant-hostmanager&hashtags=vagrant%hostmanager&original_referer=) `vagrant-hostmanager` is a Vagrant plugin that manages the `hosts` file on guest machines (and optionally the host). Its goal is to enable resolution of multi-machine environments deployed with a cloud provider where IP addresses are not known in advance. Installation ------------ $ vagrant plugin install vagrant-hostmanager Usage ----- To update the `hosts` file on each active machine, run the following command: $ vagrant hostmanager The plugin hooks into the `vagrant up` and `vagrant destroy` commands automatically. When a machine enters or exits the running state , all active machines with the same provider will have their `hosts` file updated accordingly. Set the `hostmanager.enabled` attribute to `true` in the Vagrantfile to activate this behavior. To update the host's `hosts` file, set the `hostmanager.manage_host` attribute to `true`. To update the guests' `hosts` file, set the `hostmanager.manage_guest` attribute to `true`. A machine's IP address is defined by either the static IP for a private network configuration or by the SSH host configuration. To disable using the private network IP address, set `config.hostmanager.ignore_private_ip` to true. A machine's host name is defined by `config.vm.hostname`. If this is not set, it falls back to the symbol defining the machine in the Vagrantfile. If the `hostmanager.include_offline` attribute is set to `true`, boxes that are up or have a private ip configured will be added to the hosts file. In addition, the `hostmanager.aliases` configuration attribute can be used to provide aliases for your host names. Example configuration: ```ruby Vagrant.configure("2") do |config| config.hostmanager.enabled = true config.hostmanager.manage_host = true config.hostmanager.manage_guest = true config.hostmanager.ignore_private_ip = false config.hostmanager.include_offline = true config.vm.define 'example-box' do |node| node.vm.hostname = 'example-box-hostname' node.vm.network :private_network, ip: '192.168.42.42' node.hostmanager.aliases = %w(example-box.localdomain example-box-alias) end end ``` ### Provisioner Starting at version 1.5.0, `vagrant up` runs hostmanager before any provisioning occurs. If you would like hostmanager to run after or during your provisioning stage, you can use hostmanager as a provisioner. This allows you to use the provisioning order to ensure that hostmanager runs when desired. The provisioner will collect hosts from boxes with the same provider as the running box. Example: ```ruby # Disable the default hostmanager behavior config.hostmanager.enabled = false # ... possible provisioner config before hostmanager ... # hostmanager provisioner config.vm.provision :hostmanager # ... possible provisioning config after hostmanager ... ``` Custom IP resolver ------------------ You can customize way, how host manager resolves IP address for each machine. This might be handy in case of aws provider, where host name is stored in ssh_info hash of each machine. This causes generation of invalid /etc/hosts file. Custom IP resolver gives you oportunity to calculate IP address for each machine by yourself, giving You also access to the machine that is updating /etc/hosts. For example: ```ruby config.hostmanager.ip_resolver = proc do |vm, resolving_vm| if hostname = (vm.ssh_info && vm.ssh_info[:host]) `host #{hostname}`.split("\n").last[/(\d+\.\d+\.\d+\.\d+)/, 1] end end ``` Passwordless sudo ----------------- To avoid being asked for the password every time the hosts file is updated, enable passwordless sudo for the specific command that hostmanager uses to update the hosts file. - Add the following snippet to the sudoers file (e.g. `/etc/sudoers.d/vagrant_hostmanager`): ``` Cmnd_Alias VAGRANT_HOSTMANAGER_UPDATE = /bin/cp /.vagrant.d/tmp/hosts.local /etc/hosts % ALL=(root) NOPASSWD: VAGRANT_HOSTMANAGER_UPDATE ``` Replace `` with your actual home directory (e.g. `/home/joe`) and `` with the group that is used by the system for sudo access (usually `sudo` on Debian/Ubuntu systems and `wheel` on Fedora/Red Hat systems). - If necessary, add yourself to the ``: ``` usermod -aG ``` Replace `` with the group that is used by the system for sudo access (see above) and `` with you user name. Windows support --------------- Hostmanager will detect Windows guests and hosts and use the appropriate path for the ```hosts``` file: ```%WINDIR%\System32\drivers\etc\hosts``` By default on a Windows host, the ```hosts``` file is not writable without elevated privileges. If hostmanager detects that it cannot overwrite the file, it will attempt to do so with elevated privileges, causing the [UAC](http://en.wikipedia.org/wiki/User_Account_Control) prompt to appear. To avoid the UAC prompt, open ```%WINDIR%\System32\drivers\etc\``` in Explorer, right-click the hosts file, go to Properties > Security > Edit and give your user Modify permission. ### UAC limitations Due to limitations caused by UAC, cancelling out of the UAC prompt will not cause any visible errors, however the ```hosts``` file will not be updated. Compatibility ------------- This Vagrant plugin has been tested with the following host and guest operating system combinations. Date Tested | Vagrant Version | vagrant-hostmanager Version | Host (Workstation) Operating System | Guest (VirtualBox) Operating System ------------|-----------------|-----------------------------|-------------------------------------|-------------------------------------- 03/23/2016 | 1.8.1 | 1.8.1 | Ubuntu 14.04 LTS | CentOS 7.2 03/22/2016 | 1.8.1 | 1.8.1 | OS X 10.11.4 | CentOS 7.2 05/03/2017 | 1.9.4 | 1.8.6 | macOS 10.12.4 | Windows Server 2012 R2 Troubleshooting ------------- * Version 1.1 of the plugin prematurely introduced a feature to hook into commands other than `vagrant up` and `vagrant destroy`. Version 1.1 broke support for some providers. Version 1.2 reverts this feature until a suitable implementation supporting all providers is available. * Potentially breaking change in v1.5.0: the running order on `vagrant up` has changed so that hostmanager runs before provisioning takes place. This ensures all hostnames are available to the guest when it is being provisioned (see [#73](https://github.com/devopsgroup-io/vagrant-hostmanager/issues/73)). Previously, hostmanager would run as the very last action. If you depend on the old behavior, see the [provisioner](#provisioner) section. Contribute ---------- To contribute, fork then clone the repository, and then the following: **Developing** 1. Ideally, install the version of Vagrant as defined in the `Gemfile` 1. Install [Ruby](https://www.ruby-lang.org/en/documentation/installation/) 2. Currently the Bundler version is locked to 1.14.6, please install this version. * `gem install bundler -v '1.14.6'` 3. Then install vagrant-hostmanager dependancies: * `bundle _1.14.6_ install` **Testing** 1. Build and package your newly developed code: * `rake gem:build` 2. Then install the packaged plugin: * `vagrant plugin install pkg/vagrant-hostmanager-*.gem` 3. Once you're done testing, roll-back to the latest released version: * `vagrant plugin uninstall vagrant-hostmanager` * `vagrant plugin install vagrant-hostmanager` 4. Once you're satisfied developing and testing your new code, please submit a pull request for review. **Releasing** To release a new version of vagrant-hostmanager you will need to do the following: *(only contributors of the GitHub repo and owners of the project at RubyGems will have rights to do this)* 1. First, bump, commit, and push the version in ~/lib/vagrant-hostmanager/version.rb: * Follow [Semantic Versioning](http://semver.org/). 2. Then, create a matching GitHub Release (this will also create a tag): * Preface the version number with a `v`. * https://github.com/devopsgroup-io/vagrant-hostmanager/releases 3. You will then need to build and push the new gem to RubyGems: * `rake gem:build` * `gem push pkg/vagrant-hostmanager-1.6.1.gem` 4. Then, when John Doe runs the following, they will receive the updated vagrant-hostmanager plugin: * `vagrant plugin update` * `vagrant plugin update vagrant-hostmanager` vagrant-hostmanager-1.8.9/Rakefile000066400000000000000000000003311327756071000171530ustar00rootroot00000000000000require 'bundler/gem_helper' # Change to the directory of this file. Dir.chdir(File.expand_path("../", __FILE__)) namespace :gem do Bundler::GemHelper.install_tasks end task :test do sh 'bash test/test.sh' end vagrant-hostmanager-1.8.9/lib/000077500000000000000000000000001327756071000162575ustar00rootroot00000000000000vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager.rb000066400000000000000000000005511327756071000225550ustar00rootroot00000000000000require 'vagrant-hostmanager/plugin' require 'vagrant-hostmanager/version' require 'vagrant-hostmanager/errors' module VagrantPlugins module HostManager def self.source_root @source_root ||= Pathname.new(File.expand_path('../../', __FILE__)) end I18n.load_path << File.expand_path('locales/en.yml', source_root) I18n.reload! end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/000077500000000000000000000000001327756071000222275ustar00rootroot00000000000000vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/action.rb000066400000000000000000000013571327756071000240370ustar00rootroot00000000000000require 'vagrant-hostmanager/action/update_all' require 'vagrant-hostmanager/action/update_guest' require 'vagrant-hostmanager/action/update_host' module VagrantPlugins module HostManager module Action include Vagrant::Action::Builtin def self.update_all Vagrant::Action::Builder.new.tap do |builder| builder.use ConfigValidate builder.use UpdateAll end end def self.update_guest Vagrant::Action::Builder.new.tap do |builder| builder.use ConfigValidate builder.use UpdateGuest end end def self.update_host Vagrant::Action::Builder.new.tap do |builder| builder.use UpdateHost end end end end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/action/000077500000000000000000000000001327756071000235045ustar00rootroot00000000000000vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/action/update_all.rb000066400000000000000000000033671327756071000261540ustar00rootroot00000000000000require 'vagrant-hostmanager/hosts_file/updater' require 'vagrant-hostmanager/util' module VagrantPlugins module HostManager module Action class UpdateAll def initialize(app, env) @app = app @machine = env[:machine] @global_env = @machine.env @provider = @machine.provider_name @config = Util.get_config(@global_env) @updater = HostsFile::Updater.new(@global_env, @provider) @logger = Log4r::Logger.new('vagrant::hostmanager::update_all') end def call(env) # skip if machine is not active on destroy action return @app.call(env) if !@machine.id && env[:machine_action] == :destroy # check config to see if the hosts file should be update automatically return @app.call(env) unless @config.hostmanager.enabled? @logger.info 'Updating /etc/hosts file automatically' @app.call(env) # update /etc/hosts file on active machines if @machine.config.hostmanager.manage_guest? env[:ui].info I18n.t('vagrant_hostmanager.action.update_guests') @global_env.active_machines.each do |name, p| if p == @provider machine = @global_env.machine(name, p) state = machine.state if ['active','running'].include?(state.short_description) @updater.update_guest(machine) end end end end # update /etc/hosts files on host if enabled if @machine.config.hostmanager.manage_host? env[:ui].info I18n.t('vagrant_hostmanager.action.update_host') @updater.update_host end end end end end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/action/update_guest.rb000066400000000000000000000015041327756071000265220ustar00rootroot00000000000000require 'vagrant-hostmanager/hosts_file/updater' require 'vagrant-hostmanager/util' module VagrantPlugins module HostManager module Action class UpdateGuest def initialize(app, env) @app = app global_env = env[:global_env] @config = Util.get_config(global_env) @machine = env[:machine] @updater = HostsFile::Updater.new(@machine.env, env[:provider]) @logger = Log4r::Logger.new('vagrant::hostmanager::update_guest') end def call(env) if @config.hostmanager.manage_guest? env[:ui].info I18n.t('vagrant_hostmanager.action.update_guest', { :name => @machine.name }) @updater.update_guest(@machine) @app.call(env) end end end end end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/action/update_host.rb000066400000000000000000000013551327756071000263540ustar00rootroot00000000000000require 'vagrant-hostmanager/hosts_file/updater' require 'vagrant-hostmanager/util' module VagrantPlugins module HostManager module Action class UpdateHost def initialize(app, env) @app = app global_env = env[:global_env] @config = Util.get_config(global_env) @updater = HostsFile::Updater.new(global_env, env[:provider]) @logger = Log4r::Logger.new('vagrant::hostmanager::update_host') end def call(env) if @config.hostmanager.manage_host? env[:ui].info I18n.t('vagrant_hostmanager.action.update_host') @updater.update_host end @app.call(env) end end end end endvagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/command.rb000066400000000000000000000025271327756071000242000ustar00rootroot00000000000000module VagrantPlugins module HostManager class Command < Vagrant.plugin('2', :command) # Show description when `vagrant list-commands` is triggered def self.synopsis "plugin: vagrant-hostmanager: manages the /etc/hosts file within a multi-machine environment" end def execute options = {} opts = OptionParser.new do |o| o.banner = 'Usage: vagrant hostmanager [vm-name]' o.separator '' o.version = VagrantPlugins::HostManager::VERSION o.program_name = 'vagrant hostmanager' o.on('--provider provider', String, 'Update machines with the specific provider.') do |provider| options[:provider] = provider.to_sym end end argv = parse_options(opts) options[:provider] ||= @env.default_provider # update /etc/hosts file for specified guest machines with_target_vms(argv, options) do |machine| @env.action_runner.run(Action.update_guest, { :global_env => @env, :machine => machine, :provider => options[:provider] }) end # update /etc/hosts file for host @env.action_runner.run(Action.update_host, { :global_env => @env, :provider => options[:provider] }) end end end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/config.rb000066400000000000000000000056541327756071000240330ustar00rootroot00000000000000module VagrantPlugins module HostManager class Config < Vagrant.plugin('2', :config) attr_accessor :enabled attr_accessor :manage_host attr_accessor :manage_guest attr_accessor :ignore_private_ip attr_accessor :aliases attr_accessor :include_offline attr_accessor :ip_resolver alias_method :enabled?, :enabled alias_method :include_offline?, :include_offline alias_method :manage_host?, :manage_host alias_method :manage_guest?, :manage_guest def initialize @enabled = UNSET_VALUE @manage_host = UNSET_VALUE @manage_guest = UNSET_VALUE @ignore_private_ip = UNSET_VALUE @include_offline = UNSET_VALUE @aliases = UNSET_VALUE @ip_resolver = UNSET_VALUE end def finalize! @enabled = false if @enabled == UNSET_VALUE @manage_host = false if @manage_host == UNSET_VALUE @manage_guest = true if @manage_guest == UNSET_VALUE @ignore_private_ip = false if @ignore_private_ip == UNSET_VALUE @include_offline = false if @include_offline == UNSET_VALUE @aliases = [] if @aliases == UNSET_VALUE @ip_resolver = nil if @ip_resolver == UNSET_VALUE @aliases = [ @aliases ].flatten end def validate(machine) errors = [] errors << validate_bool('hostmanager.enabled', @enabled) errors << validate_bool('hostmanager.manage_host', @manage_host) errors << validate_bool('hostmanager.manage_guest', @manage_guest) errors << validate_bool('hostmanager.ignore_private_ip', @ignore_private_ip) errors << validate_bool('hostmanager.include_offline', @include_offline) errors.compact! # check if aliases option is an Array if !machine.config.hostmanager.aliases.kind_of?(Array) && !machine.config.hostmanager.aliases.kind_of?(String) errors << I18n.t('vagrant_hostmanager.config.not_an_array_or_string', { :config_key => 'hostmanager.aliases', :is_class => aliases.class.to_s, }) end if !machine.config.hostmanager.ip_resolver.nil? && !machine.config.hostmanager.ip_resolver.kind_of?(Proc) errors << I18n.t('vagrant_hostmanager.config.not_a_proc', { :config_key => 'hostmanager.ip_resolver', :is_class => ip_resolver.class.to_s, }) end errors.compact! { "HostManager configuration" => errors } end private def validate_bool(key, value) if ![TrueClass, FalseClass].include?(value.class) && value != UNSET_VALUE I18n.t('vagrant_hostmanager.config.not_a_bool', { :config_key => key, :value => value.class.to_s }) else nil end end end end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/errors.rb000066400000000000000000000001171327756071000240670ustar00rootroot00000000000000module VagrantPlugins module HostManager module Errors end end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/hosts_file/000077500000000000000000000000001327756071000243665ustar00rootroot00000000000000vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/hosts_file/updater.rb000066400000000000000000000201161327756071000263570ustar00rootroot00000000000000require 'tempfile' module VagrantPlugins module HostManager module HostsFile class Updater def initialize(global_env, provider) @global_env = global_env @config = Util.get_config(@global_env) @provider = provider @logger = Log4r::Logger.new('vagrant::hostmanager::updater') @logger.debug("init updater") end def update_guest(machine) return unless machine.communicate.ready? if (machine.communicate.test("uname -s | grep SunOS")) realhostfile = "/etc/inet/hosts" line_endings = "lf" elsif (machine.communicate.test("test -d $Env:SystemRoot")) windir = "" machine.communicate.execute("echo %SYSTEMROOT%", {:shell => :cmd}) do |type, contents| windir << contents.gsub("\r\n", '') if type == :stdout end realhostfile = "#{windir}\\System32\\drivers\\etc\\hosts" line_endings = "crlf" else realhostfile = "/etc/hosts" line_endings = "lf" end # download and modify file with Vagrant-managed entries file = @global_env.tmp_path.join("hosts.#{machine.name}") machine.communicate.download(realhostfile, file) @logger.debug("file is: #{file.to_s}") @logger.debug("class of file is: #{file.class}") if update_file(file, machine, false, line_endings) # upload modified file and remove temporary file machine.communicate.upload(file.to_s, "/tmp/hosts.#{machine.name}") if windir machine.communicate.sudo("mv -force /tmp/hosts.#{machine.name} #{realhostfile}") else machine.communicate.sudo("cat /tmp/hosts.#{machine.name} > #{realhostfile} && rm -f /tmp/hosts.#{machine.name}") end end end def update_host # copy and modify hosts file on host with Vagrant-managed entries file = @global_env.tmp_path.join('hosts.local') if WindowsSupport.windows? # lazily include windows Module class << self include WindowsSupport unless include? WindowsSupport end hosts_location = "#{ENV['WINDIR']}\\System32\\drivers\\etc\\hosts" copy_proc = Proc.new { windows_copy_file(file, hosts_location) } line_endings = "crlf" else hosts_location = '/etc/hosts' copy_proc = Proc.new { `[ -w "#{hosts_location}" ] && cat "#{file}" > "#{hosts_location}" || sudo cp "#{file}" "#{hosts_location}"` } line_endings = "lf" end FileUtils.cp(hosts_location, file) if update_file(file, nil, true, line_endings) copy_proc.call end end private def update_file(file, resolving_machine = nil, include_id = true, line_endings) file = Pathname.new(file) old_file_content = file.read new_file_content = update_content(old_file_content, resolving_machine, include_id, line_endings) file.open('wb') { |io| io.write(new_file_content) } old_file_content != new_file_content end def update_content(file_content, resolving_machine, include_id, line_endings) id = include_id ? " id: #{read_or_create_id}" : "" header = "## vagrant-hostmanager-start#{id}" footer = "## vagrant-hostmanager-end" body = get_machines .map { |machine| get_hosts_file_entry(machine, resolving_machine) } .join get_new_content(header, footer, body, file_content, line_endings) end def get_hosts_file_entry(machine, resolving_machine) ip = get_ip_address(machine, resolving_machine) host = machine.config.vm.hostname || machine.name aliases = machine.config.hostmanager.aliases if ip != nil "#{ip}\t#{host}\n" + aliases.map{|a| "#{ip}\t#{a}"}.join("\n") + "\n" end end def get_ip_address(machine, resolving_machine) custom_ip_resolver = machine.config.hostmanager.ip_resolver if custom_ip_resolver custom_ip_resolver.call(machine, resolving_machine) else ip = nil if machine.config.hostmanager.ignore_private_ip != true machine.config.vm.networks.each do |network| key, options = network[0], network[1] ip = options[:ip] if key == :private_network break if ip end end ip || (machine.ssh_info ? machine.ssh_info[:host] : nil) end end def get_machines if @config.hostmanager.include_offline? machines = @global_env.machine_names else machines = @global_env.active_machines .select { |name, provider| provider == @provider } .collect { |name, provider| name } end # Collect only machines that exist for the current provider machines.collect do |name| begin machine = @global_env.machine(name, @provider) rescue Vagrant::Errors::MachineNotFound # ignore end machine end .reject(&:nil?) end def get_new_content(header, footer, body, old_content, line_endings) if body.empty? block = "\n" else block = "\n\n" + header + "\n" + body + footer + "\n\n" end # Pattern for finding existing block header_pattern = Regexp.quote(header) footer_pattern = Regexp.quote(footer) pattern = Regexp.new("[\r\n]*#{header_pattern}.*?#{footer_pattern}[\r\n]*", Regexp::MULTILINE) # Replace existing block or append content = old_content.match(pattern) ? old_content.sub(pattern, block) : old_content.rstrip + block if line_endings == "crlf" content.encode(content.encoding, :universal_encoding => true).encode(content.encoding, :crlf_newline => true) elsif line_endings == "lf" content.encode(content.encoding, :universal_encoding => true) else content.encode(content.encoding, :universal_encoding => true) end end def read_or_create_id file = Pathname.new("#{@global_env.local_data_path}/hostmanager/id") if (file.file?) id = file.read.strip else id = SecureRandom.uuid file.dirname.mkpath file.open('w') { |io| io.write(id) } end id end ## Windows support for copying files, requesting elevated privileges if necessary module WindowsSupport require 'rbconfig' def self.windows? RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/ end require 'win32ole' if windows? def windows_copy_file(source, dest) begin # First, try Ruby copy FileUtils.cp(source, dest) rescue Errno::EACCES # Access denied, try with elevated privileges windows_copy_file_elevated(source, dest) end end private def windows_copy_file_elevated(source, dest) # copy command only supports backslashes as separators source, dest = [source, dest].map { |s| s.to_s.gsub(/\//, '\\') } # run 'cmd /C copy ...' with elevated privilege, minimized copy_cmd = "copy \"#{source}\" \"#{dest}\"" WIN32OLE.new('Shell.Application').ShellExecute('cmd', "/C #{copy_cmd}", nil, 'runas', 7) # Unfortunately, ShellExecute does not give us a status code, # and it is non-blocking so we can't reliably compare the file contents # to see if they were copied. # # If the user rejects the UAC prompt, vagrant will silently continue # without updating the hostsfile. end end end end end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/plugin.rb000066400000000000000000000022751327756071000240600ustar00rootroot00000000000000require 'vagrant-hostmanager/action' module VagrantPlugins module HostManager class Plugin < Vagrant.plugin('2') name 'HostManager' description <<-DESC This plugin manages the /etc/hosts file for the host and guest machines. An entry is created for each running machine using the hostname attribute. You can also use the hostmanager provisioner to update the hosts file. DESC config(:hostmanager) do require_relative 'config' Config end action_hook(:hostmanager, :machine_action_up) do |hook| hook.after(Vagrant::Action::Builtin::Provision, Action.update_all) end action_hook(:hostmanager, :machine_action_destroy) do |hook| hook.prepend(Action.update_all) end provisioner(:hostmanager) do require_relative 'provisioner' Provisioner end # Work-around for vagrant >= 1.5 # It breaks without a provisioner config, so we provide a dummy one config(:hostmanager, :provisioner) do ::Vagrant::Config::V2::DummyConfig.new end command(:hostmanager) do require_relative 'command' Command end end end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/provisioner.rb000066400000000000000000000011561327756071000251360ustar00rootroot00000000000000require 'vagrant-hostmanager/hosts_file/updater' module VagrantPlugins module HostManager class Provisioner < Vagrant.plugin('2', :provisioner) def initialize(machine, config) super(machine, config) global_env = machine.env @config = Util.get_config(global_env) @updater = HostsFile::Updater.new(global_env, machine.provider_name) end def provision if @config.hostmanager.manage_guest? @updater.update_guest(@machine) end if @config.hostmanager.manage_host? @updater.update_host end end end end end vagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/util.rb000066400000000000000000000005111327756071000235260ustar00rootroot00000000000000module VagrantPlugins module HostManager module Util def self.get_config(env) # config_global has been removed from v1.5 if Gem::Version.new(::Vagrant::VERSION) >= Gem::Version.new('1.5') env.vagrantfile.config else env.config_global end end end end endvagrant-hostmanager-1.8.9/lib/vagrant-hostmanager/version.rb000066400000000000000000000001131327756071000242340ustar00rootroot00000000000000module VagrantPlugins module HostManager VERSION = '1.8.9' end end vagrant-hostmanager-1.8.9/locales/000077500000000000000000000000001327756071000171335ustar00rootroot00000000000000vagrant-hostmanager-1.8.9/locales/en.yml000066400000000000000000000014051327756071000202600ustar00rootroot00000000000000en: vagrant_hostmanager: action: update_guests: "[vagrant-hostmanager:guests] Updating hosts file on active guest virtual machines..." update_guest: "[vagrant-hostmanager:guest] Updating hosts file on the virtual machine %{name}..." update_host: "[vagrant-hostmanager:host] Updating hosts file on your workstation (password may be required)..." config: not_a_bool: "[vagrant-hostmanager:config:error] A value for %{config_key} can only be true or false, not type '%{value}'" not_an_array_or_string: "[vagrant-hostmanager:config:error] A value for %{config_key} must be an Array or String, not type '%{is_class}'" not_a_proc: "[vagrant-hostmanager:config:error] A value for %{config_key} must be a Proc, not type '%{is_class}'" vagrant-hostmanager-1.8.9/test/000077500000000000000000000000001327756071000164705ustar00rootroot00000000000000vagrant-hostmanager-1.8.9/test/Vagrantfile000066400000000000000000000022211327756071000206520ustar00rootroot00000000000000# -*- mode: ruby -*- # vi: set ft=ruby : if Gem::Version.new(::Vagrant::VERSION) < Gem::Version.new('1.5') Vagrant.require_plugin('vagrant-hostmanager') end Vagrant.configure('2') do |config| if ENV.key? 'VAGRANT_BOX' config.vm.box = ENV['VAGRANT_BOX'] else config.vm.box = 'precise64' config.vm.box_url = 'http://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-vagrant-amd64-disk1.box' end config.hostmanager.enabled = true config.hostmanager.manage_host = true config.hostmanager.manage_guest = true config.vm.define :server1 do |server| server.vm.hostname = 'fry' server.vm.network :private_network, :ip => '10.0.5.2' server.hostmanager.aliases = %w(test-alias) end config.vm.define :server2 do |server| server.vm.hostname = 'bender' server.vm.network :private_network, :ip => '10.0.5.3' end config.vm.define :server3 do |server| server.vm.hostname = 'leena' server.vm.network :private_network, :ip => '10.0.5.4' server.vm.provision :hostmanager end config.vm.define :server4 do |server| server.vm.hostname = 'scruffy' server.vm.provision :hostmanager end end vagrant-hostmanager-1.8.9/test/test.sh000077500000000000000000000003311327756071000200030ustar00rootroot00000000000000cd test vagrant up vagrant hostmanager echo "[server1] /etc/hosts file:" vagrant ssh server1 -c 'cat /etc/hosts' echo "[server2] /etc/hosts file:" vagrant ssh server2 -c 'cat /etc/hosts' vagrant destroy -f cd .. vagrant-hostmanager-1.8.9/vagrant-hostmanager.gemspec000066400000000000000000000015031327756071000230250ustar00rootroot00000000000000# -*- encoding: utf-8 -*- lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'vagrant-hostmanager/version' Gem::Specification.new do |gem| gem.name = 'vagrant-hostmanager' gem.version = VagrantPlugins::HostManager::VERSION gem.authors = ['Shawn Dahlen','Seth Reeser'] gem.email = ['shawn@dahlen.me','info@devopsgroup.io'] gem.description = %q{A Vagrant plugin that manages the /etc/hosts file within a multi-machine environment} gem.summary = gem.description gem.license = 'MIT' gem.files = `git ls-files`.split($/) gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.require_paths = ['lib'] gem.add_development_dependency 'bundler', '~> 1.3' gem.add_development_dependency 'rake' end