Merge branch 'jlm/sync_folder'

This commit is contained in:
Ramakrishnan 2014-05-09 12:31:51 +05:30
Родитель 3ee7813917 a17334d985
Коммит d15326a4b0
17 изменённых файлов: 319 добавлений и 56 удалений

24
CHANGELOG.md Normal file
Просмотреть файл

@ -0,0 +1,24 @@
## 1.0.5 (Unreleased)
FEATURES
- Provision for windows VM.
- Windows VM has to be specifically mentioned in the Vagrantfile with
`config.vm.guest = :windows`
- Chef, Puppet and Shell provision for Linux and Windows VM.
- **SyncedFolders**
- Linux VM uses `rsync` and has be mentioned in the VagrantFile.
- Windows VM will default to use PowerShell to copy files.
IMPROVEMENTS
- Better exception handling when VM fails to get created in cloud.
- Better exception handling for WinRM session errors.
BUGFIXES
- Cleaned up few typo in README
- Compatible with Vagrant 1.6 [GH-15]
## Previous
See git commits

Просмотреть файл

@ -13,7 +13,3 @@ group :development do
# Vagrant environment itself using `vagrant plugin`.
gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git"
end
group :plugins do
gem 'vagrant-azure', path: '.'
end

Просмотреть файл

@ -12,10 +12,17 @@ module VagrantPlugins
autoload :Errors, lib_path.join('errors')
autoload :Driver, lib_path.join('driver')
# Load a communicator for Windows guest
require lib_path.join("communication/powershell")
require lib_path.join('provisioner/puppet')
require lib_path.join('provisioner/chef-solo')
require lib_path.join('provisioner/shell')
monkey_patch = Pathname.new(File.expand_path("../vagrant-azure/monkey_patch", __FILE__))
# Monkey Patch the core Hyper-V vagrant with the following
require monkey_patch.join("machine")
# This returns the path to the source of this plugin.
#
# @return [Pathname]

Просмотреть файл

@ -65,14 +65,12 @@ module VagrantPlugins
b2.use Message, I18n.t('vagrant_azure.not_created')
next
end
b2.use Provision
# b2.use SyncFolders
end
end
end
# This action is called to read the SSH info of the machine. The
# This action is called to read the SSH info of the machine. The
# resulting state is expected to be put into the `:machine_ssh_info` key.
def self.action_read_ssh_info
Vagrant::Action::Builder.new.tap do |b|
@ -158,32 +156,33 @@ module VagrantPlugins
def self.action_prepare_boot
Vagrant::Action::Builder.new.tap do |b|
b.use Provision
# b.use SyncFolders
# b.use WarnNetworks
b.use Call, WaitForState, :ReadyRole do |env, b1|
if env[:result]
env[:machine].id =~ /@/
b1.use Message, I18n.t(
'vagrant_azure.vm_started', :name => $`
)
b1.use WaitForCommunicate
b1.use Provision
b1.use SyncFolders
end
end
end
end
# This action is called to bring the box up from nothing
def self.action_up
Vagrant::Action::Builder.new.tap do |b|
b.use HandleBoxUrl
b.use HandleBox
b.use ConfigValidate
b.use ConnectAzure
b.use Call, IsState, :NotCreated do |env1, b1|
if !env1[:result]
b1.use Call, IsState, :StoppedDeallocated do |env2, b2|
if env2[:result]
b2.use action_prepare_boot
b2.use StartInstance # start this instance again
b2.use Call, WaitForState, :ReadyRole do |env3, b3|
if env3[:result]
env3[:machine].id =~ /@/
b3.use Message, I18n.t(
'vagrant_azure.vm_started', :name => $`
)
end
end
b2.use action_prepare_boot
else
b2.use Message, I18n.t(
'vagrant_azure.already_status', :status => 'created'
@ -192,14 +191,7 @@ module VagrantPlugins
end
else
b1.use RunInstance # Launch a new instance
b1.use Call, WaitForState, :ReadyRole do |env2, b2|
if env2[:result]
env2[:machine].id =~ /@/
b2.use Message, I18n.t(
'vagrant_azure.vm_started', :name => $`
)
end
end
b1.use action_prepare_boot
end
end
end
@ -240,11 +232,12 @@ module VagrantPlugins
autoload :RunInstance, action_root.join('run_instance')
autoload :StartInstance, action_root.join('start_instance')
autoload :StopInstance, action_root.join('stop_instance')
# autoload :SyncFolders, action_root.join('sync_folders')
autoload :SyncFolders, action_root.join('sync_folders')
autoload :TerminateInstance, action_root.join('terminate_instance')
# autoload :TimedProvision, action_root.join('timed_provision')
# autoload :WarnNetworks, action_root.join('warn_networks')
autoload :WaitForState, action_root.join('wait_for_state')
autoload :WaitForCommunicate, action_root.join('wait_for_communicate')
end
end
end

Просмотреть файл

@ -5,6 +5,11 @@
require 'azure'
require 'log4r'
# FIXME:
# This is a required to patch few exception handling which are not done in
# Azure Ruby SDK
require_relative "vagrant_azure_service"
module VagrantPlugins
module WinAzure
module Action
@ -17,11 +22,6 @@ module VagrantPlugins
def call (env)
config = env[:machine].provider_config
env[:ui].warn "Subscription ID: [#{config.subscription_id}]"
env[:ui].warn "Mangement Certificate: [#{config.mgmt_certificate}]"
env[:ui].warn "Mangement Endpoint: [#{config.mgmt_endpoint}]"
env[:ui].warn "Storage Account Name: [#{config.storage_acct_name}]"
Azure.configure do |c|
c.subscription_id = config.subscription_id
c.management_certificate = config.mgmt_certificate
@ -30,7 +30,13 @@ module VagrantPlugins
c.storage_access_key = config.storage_access_key
end
env[:azure_vm_service] = Azure::VirtualMachineManagementService.new
# FIXME:
# Defining a new class VagrantAzureService
# Here we call the native azure virtual machine management service method
# and add some exception handling.
# Remove this once the Azure SDK adds the exception handling for the
# methods defined in VagrantAzureService
env[:azure_vm_service] = VagrantAzureService.new(Azure::VirtualMachineManagementService.new)
@app.call(env)
end

Просмотреть файл

@ -102,8 +102,7 @@ module VagrantPlugins
# machine as a string.
if server.instance_of? String
env[:ui].info "Server not created. Error is: #{server}"
raise Errors::CreateVMError, message: "#{server}"
raise Errors::ServerNotCreated, message: server
end
env[:machine].id = "#{server.vm_name}@#{server.cloud_service_name}"

Просмотреть файл

@ -0,0 +1,63 @@
# Copyright (c) 2014 Mitchell Hashimoto
# Under The MIT License (MIT)
#---------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache 2.0 License.
#--------------------------------------------------------------------------
require "log4r"
require "vagrant/util/subprocess"
require "vagrant/util/scoped_hash_override"
require "vagrant/util/which"
require "#{Vagrant::source_root}/lib/vagrant/action/builtin/synced_folders"
module VagrantPlugins
module WinAzure
module Action
# This middleware uses `rsync` to sync the folders
class SyncFolders < Vagrant::Action::Builtin::SyncedFolders
include Vagrant::Util::ScopedHashOverride
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant_azure::action::sync_folders")
end
def call(env)
if env[:machine].config.vm.guest != :windows
super
else
@app.call(env)
env[:machine].config.vm.synced_folders.each do |id, data|
data = scoped_hash_override(data, :azure)
# Ignore disabled shared folders
next if data[:disabled]
hostpath = File.expand_path(data[:hostpath], env[:root_path])
guestpath = data[:guestpath]
env[:ui].info(I18n.t("vagrant_azure.copy_folder",
:hostpath => hostpath,
:guestpath => guestpath))
# Create the host path if it doesn't exist and option flag is set
if data[:create]
begin
FileUtils::mkdir_p(hostpath)
rescue => err
raise Errors::MkdirError,
:hostpath => hostpath,
:err => err
end
end
env[:machine].provider.driver.upload(hostpath, guestpath)
end
end
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,43 @@
#---------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache 2.0 License.
#--------------------------------------------------------------------------
# FIXME:
# This is a stop gap arrangement until the azure ruby SDK fixes the exceptions
# and gracefully fails.
module VagrantPlugins
module WinAzure
module Action
class VagrantAzureService
attr_reader :azure
def initialize(azure)
@azure = azure
end
# At times due to network latency the SDK raises SocketError, this can
# be rescued and re-try for three attempts.
def get_virtual_machine(*args)
vm = nil
attempt = 0
while true
begin
vm = azure.get_virtual_machine(*args)
rescue SocketError
attempt = attempt + 1
sleep 5
next if attempt < 3
end
break
end
vm
end
def method_missing(method, *args, &block)
azure.send(method, *args, &block)
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,38 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache 2.0 License.
#--------------------------------------------------------------------------
require 'log4r'
require 'timeout'
module VagrantPlugins
module WinAzure
module Action
class WaitForCommunicate
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant_azure::action::wait_for_communicate")
end
def call(env)
if !env[:interrupted]
# Wait for SSH to be ready.
env[:ui].info(I18n.t("vagrant_azure.waiting_for_ssh"))
while true
# If we're interrupted then just back out
break if env[:interrupted]
break if env[:machine].communicate.ready?
sleep 5
end
# Ready and booted!
env[:ui].info(I18n.t("vagrant_azure.ssh_ready"))
end
@app.call(env)
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,41 @@
#-------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache 2.0 License.
#--------------------------------------------------------------------------
module VagrantPlugins
module WinAzure
module Communicator
class PowerShell < Vagrant.plugin("2", :communicator)
def initialize(machine)
@machine = machine
end
def wait_for_ready(timeout)
ready?
end
def ready?
# Return True when the guest has enabled WinRM
# In this case we can try any remote PowerShell commands to see if
# further vagrant can be carried out using this communication
if !@winrm_status
status = false
response = @machine.provider.driver.check_winrm
message = nil
if response && response["message"]
message = response["message"]
@winrm_status = message == "Running"
end
raise Errors::WinRMNotReady, message: message if !@winrm_status
end
@winrm_status
end
def test(command, opts=nil)
true
end
end
end
end
end

Просмотреть файл

@ -96,7 +96,7 @@ module VagrantPlugins
@state_read_timeout = 360 if @state_read_timeout == UNSET_VALUE
# This done due to a bug in Ruby SDK - it doesn't generate a storage
# This done due to a bug in Ruby SDK - it doesn't generate a storage
# account name if add_role = true
if @storage_acct_name.nil? || @storage_acct_name.empty?
@storage_acct_name = Azure::Core::Utility.random_string(
@ -119,7 +119,7 @@ module VagrantPlugins
self.mgmt_endpoint
result.subscription_id = other.subscription_id || \
self.subscription_id
result.storage_account_name = other.storage_acct_name || \
result.storage_acct_name = other.storage_acct_name || \
self.storage_acct_name
result.storage_access_key = other.storage_access_key || \
self.storage_access_key

Просмотреть файл

@ -60,6 +60,11 @@ module VagrantPlugins
execute(script_path, options)
end
def check_winrm
script_path = local_script_path('check_winrm.ps1')
execute(script_path, remote_credentials)
end
protected
def local_script_path(path)

Просмотреть файл

@ -1,21 +1,27 @@
#--------------------------------------------------------------------------
#-------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache 2.0 License.
#--------------------------------------------------------------------------
module VagrantPlugins
module WinAzure
module Errors
class VagrantAzureError < Vagrant::Errors::VagrantError
class WinAzureError < Vagrant::Errors::VagrantError
error_namespace("vagrant_azure.errors")
end
class CreateVMFailure < VagrantAzureError
class WinRMNotReady < WinAzureError
error_key(:win_rm_not_ready)
end
class ServerNotCreated < WinAzureError
error_key(:server_not_created)
end
class CreateVMFailure < WinAzureError
error_key(:create_vm_failure)
end
class CreateVMError < VagrantAzureError
error_key(:create_vm_error)
end
end
end
end

Просмотреть файл

@ -0,0 +1,22 @@
#-------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache 2.0 License.
#--------------------------------------------------------------------------
module Vagrant
class Machine
ssh_communicate = instance_method(:communicate)
define_method(:communicate) do
unless @communicator
if @config.vm.guest == :windows
@communicator = VagrantPlugins::WinAzure::Communicator::PowerShell.new(self)
else
@communicator = ssh_communicate.bind(self).()
end
end
@communicator
end
end
end

Просмотреть файл

@ -2,10 +2,12 @@
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache 2.0 License.
#--------------------------------------------------------------------------
param (
[string]$guest_ip = $(throw "-guest_ip is required."),
[string]$username = $(throw "-guest_username is required."),
[string]$password = $(throw "-guest_password is required.")
[string]$password = $(throw "-guest_password is required."),
[string]$guest_port = $(throw "-guest_port is required")
)
# Include the following modules
@ -14,10 +16,14 @@ $presentDir = Split-Path -parent $PSCommandPath
. ([System.IO.Path]::Combine($presentDir, "utils\create_session.ps1"))
try {
$response = Create-Remote-Session $guest_ip $username $password
$response = Create-Remote-Session $guest_ip $guest_port $username $password
if (!$response["session"] -and $response["error"]) {
Write-Host $response["error"]
return
$session_message = $response['error']
$resultHash = @{
message = "$session_message"
}
Write-Output-Message $resultHash
return
}
function Remote-Execute() {
$winrm_state = ""
@ -34,7 +40,7 @@ try {
} catch {
$errortHash = @{
type = "PowerShellError"
error ="Failed to copy file $_"
error ="$_"
}
Write-Error-Message $errortHash
return

Просмотреть файл

@ -5,6 +5,6 @@
module VagrantPlugins
module WinAzure
VERSION = '1.0.4'
VERSION = '1.0.5'
end
end

Просмотреть файл

@ -14,10 +14,24 @@ en:
VM '%{name}' has been started
vm_stopped: |-
VM '%{name}' has been stopped
copy_folder: |-
Copying folder: %{hostpath} ==>
%{guestpath}
rsync_not_found_warning: |-
Warning! Folder sync disabled because the rsync binary is missing in the %{side}.
Make sure rsync is installed and the binary can be found in the PATH.
waiting_for_ssh: |-
Waiting for SSH
ssh_ready: |-
SSH Ready
read_attempt: |-
Failed to connect to Virtual Machine. Re-Connecting %{attempt}
errors:
create_vm_failure: |-
There was some error in creating the VM, this could be due to some network latency.
Generally the next vagrant up command should fix this error.
create_vm_error: |-
Failed to create a VM in azure cloud with the following message.
win_rm_not_ready: |-
Vagrant failed to communicate to the VM using powershell. The operation failed
with the following message.
%{message}
server_not_created: |-
Server not created. Error is: %{message}
create_vm_failure: |-
There was some error in creating the VM.