This commit is contained in:
David Justice 2016-03-26 17:37:37 -07:00
Родитель 1c0916c19f
Коммит 8d7dd2f7de
44 изменённых файлов: 876 добавлений и 989 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -17,3 +17,4 @@ modules/
*.pem
.ruby-version
*.ps1
.env

2
.rspec Normal file
Просмотреть файл

@ -0,0 +1,2 @@
--color
--require spec_helper

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

@ -1,8 +1,6 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
source 'https://rubygems.org'
@ -12,7 +10,8 @@ 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: 'git://github.com/mitchellh/vagrant.git', tag: 'v1.7.3'
gem 'vagrant', git: 'git://github.com/mitchellh/vagrant.git', tag: 'v1.7.4'
gem 'dotenv'
end
group :plugins do

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

@ -1,4 +1,21 @@
Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use these files except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
The MIT License (MIT)
Copyright (c) 2015 Microsoft
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

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

@ -1,8 +1,6 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'rubygems'
require 'bundler/setup'

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

@ -1,19 +1,14 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'pathname'
require 'vagrant-azure/plugin'
module VagrantPlugins
module WinAzure
module Azure
lib_path = Pathname.new(File.expand_path('../vagrant-azure', __FILE__))
autoload :Action, lib_path.join('action')
autoload :Errors, lib_path.join('errors')
autoload :Driver, lib_path.join('driver')
CLOUD_SERVICE_SEMAPHORE = Mutex.new
# This returns the path to the source of this plugin.
#

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

@ -1,15 +1,13 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'pathname'
require 'vagrant/action/builder'
require 'vagrant/action/builtin/wait_for_communicator'
module VagrantPlugins
module WinAzure
module Azure
module Action
# Include the built-in modules so we can use them as top-level things.
include Vagrant::Action::Builtin
@ -18,9 +16,9 @@ module VagrantPlugins
def self.action_halt
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use Call, IsState, :NotCreated do |env, b2|
if env[:result]
b2.use Message, I18n.t('vagrant_azure.not_created')
b.use Call, IsCreated do |env, b2|
unless env[:result]
b2.use MessageNotCreated
next
end
@ -36,22 +34,17 @@ module VagrantPlugins
b.use Call, DestroyConfirm do |env, b2|
if env[:result]
b2.use ConfigValidate
b2.use Call, IsState, :NotCreated do |env2, b3|
if env2[:result]
b3.use Message, I18n.t('vagrant_azure.not_created')
b2.use Call, IsCreated do |env2, b3|
unless env2[:result]
b3.use MessageNotCreated
next
end
b3.use ConnectAzure
b3.use TerminateInstance
b3.use ProvisionerCleanup if defined?(ProvisionerCleanup)
end
b2.use ConnectAzure
b2.use TerminateInstance
b2.use ProvisionerCleanup if defined?(ProvisionerCleanup)
else
env[:machine].id =~ /@/
b2.use Message, I18n.t(
'vagrant_azure.will_not_destroy',
:name => $`
)
b2.use MessageWillNotDestroy
end
end
end
@ -60,18 +53,14 @@ module VagrantPlugins
# This action is called when `vagrant provision` is called.
def self.action_provision
Vagrant::Action::Builder.new.tap do |b|
b.use ConnectAzure
b.use ConfigValidate
b.use OSType
b.use ReadWinrmInfo
b.use Call, IsState, :NotCreated do |env, b2|
if env[:result]
b2.use Message, I18n.t('vagrant_azure.not_created')
b.use Call, IsCreated do |env, b2|
unless env[:result]
b2.use MessageNotCreated
next
end
b2.use Provision
b2.use SyncFolders
end
end
end
@ -82,27 +71,13 @@ module VagrantPlugins
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectAzure
b.use ReadSSHInfo, 22
end
end
def self.action_read_rdp_info
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectAzure
b.use ReadSSHInfo, 3389
end
end
def self.action_read_winrm_info
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectAzure
b.use OSType
b.use ReadWinrmInfo
b.use ReadSSHInfo
end
end
# This action is called to read the state of the machine. The
# resulting state is expected to be put into the `:machine_state_id`
# key.
def self.action_read_state
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
@ -111,14 +86,13 @@ module VagrantPlugins
end
end
# This action is called to SSH into the machine
# This action is called to SSH into the machine.
def self.action_ssh
Vagrant::Action::Builder.new.tap do |b|
b.use ConnectAzure
b.use ConfigValidate
b.use Call, IsState, :NotCreated do |env, b2|
if env[:result]
b2.use Message, I18n.t('vagrant_azure.not_created')
b.use Call, IsCreated do |env, b2|
unless env[:result]
b2.use MessageNotCreated
next
end
@ -127,49 +101,12 @@ module VagrantPlugins
end
end
def self.action_powershell_run
Vagrant::Action::Builder.new.tap do |b|
b.use action_read_winrm_info
b.use Call, IsState, :NotCreated do |env, b2|
if env[:result]
b2.use Message, I18n.t('vagrant_azure.not_created')
next
end
b2.use PowerShellRun
end
end
end
def self.action_rdp
Vagrant::Action::Builder.new.tap do |b|
b.use ConnectAzure
b.use ConfigValidate
b.use Call, IsState, :NotCreated do |env1, b1|
if env1[:result]
b1.use Message, I18n.t('vagrant_azure.not_created')
next
end
b1.use Call, IsState, :ReadyRole do |env2, b2|
if !env2[:result]
b2.use Message, I18n.t('vagrant_azure.rdp_not_ready')
next
end
b2.use Rdp
end
end
end
end
def self.action_ssh_run
Vagrant::Action::Builder.new.tap do |b|
b.use ConnectAzure
b.use ConfigValidate
b.use Call, IsState, :NotCreated do |env, b2|
if env[:result]
b2.use Message, I18n.t('vagrant_azure.not_created')
b.use Call, IsCreated do |env, b2|
unless env[:result]
b2.use MessageNotCreated
next
end
@ -180,42 +117,31 @@ module VagrantPlugins
def self.action_prepare_boot
Vagrant::Action::Builder.new.tap do |b|
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 action_read_winrm_info
b1.use WaitForCommunicator
b1.use action_provision
end
end
b.use Provision
b.use SyncedFolders
end
end
# This action is called to bring the box up from nothing
# This action is called to bring the box up from nothing.
def self.action_up
Vagrant::Action::Builder.new.tap do |b|
b.use HandleBox
b.use ConfigValidate
b.use BoxCheckOutdated
b.use ConnectAzure
b.use OSType
b.use Call, IsState, :NotCreated do |env1, b1|
if !env1[:result]
b1.use Call, IsState, :StoppedDeallocated do |env2, b2|
b.use Call, IsCreated do |env1, b1|
if env1[:result]
b1.use Call, IsStopped do |env2, b2|
if env2[:result]
b2.use StartInstance # start this instance again
b2.use action_prepare_boot
b2.use StartInstance # restart this instance
else
b2.use Message, I18n.t(
'vagrant_azure.already_status', :status => 'created'
)
b2.use MessageAlreadyCreated
end
end
else
b1.use RunInstance # Launch a new instance
b1.use action_prepare_boot
b1.use RunInstance # launch a new instance
end
end
end
@ -225,20 +151,18 @@ module VagrantPlugins
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectAzure
b.use Call, IsState, :NotCreated do |env, b2|
if env[:result]
b2.use Message, I18n.t('vagrant_azure.not_created')
b.use Call, IsCreated do |env, b2|
unless env[:result]
b2.use MessageNotCreated
next
end
b2.use action_halt
b2.use Call, WaitForState, :StoppedDeallocated do |env2, b3|
b2.use Call, WaitForState, :stopped, 120 do |env2, b3|
if env2[:result]
env2[:machine].id =~ /@/
b3.use Message, I18n.t('vagrant_azure.vm_stopped', name: $`)
b3.use action_up
else
b3.use Message, 'Not able to stop the machine. Please retry.'
# ??? it didn't stop
end
end
end
@ -248,18 +172,19 @@ module VagrantPlugins
# The autoload farm
action_root = Pathname.new(File.expand_path('../action', __FILE__))
autoload :ConnectAzure, action_root.join('connect_azure')
autoload :Rdp, action_root.join('rdp')
autoload :IsCreated, action_root.join('is_created')
autoload :IsStopped, action_root.join('is_stopped')
autoload :MessageAlreadyCreated, action_root.join('message_already_created')
autoload :MessageNotCreated, action_root.join('message_not_created')
autoload :MessageWillNotDestroy, action_root.join('message_will_not_destroy')
autoload :ReadSSHInfo, action_root.join('read_ssh_info')
autoload :ReadWinrmInfo, action_root.join('read_winrm_info')
autoload :PowerShellRun, action_root.join('powershell_run')
autoload :OSType, action_root.join('os_type')
autoload :ReadState, action_root.join('read_state')
autoload :RestartVM, action_root.join('restart_vm')
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 :TerminateInstance, action_root.join('terminate_instance')
autoload :TimedProvision, action_root.join('timed_provision')
autoload :WaitForState, action_root.join('wait_for_state')
end
end

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

@ -1,44 +1,23 @@
#---------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
require 'azure'
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require_relative '../services/azure_resource_manager'
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 Azure
module Action
class ConnectAzure
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_azure::action::connect_aws')
@logger = Log4r::Logger.new('vagrant_azure::action::connect_azure')
end
def call (env)
if env[:azure_vm_service].nil?
if env[:azure_arm_service].nil?
config = env[:machine].provider_config
Azure.configure do |c|
c.subscription_id = config.subscription_id
c.management_certificate = config.mgmt_certificate
c.management_endpoint = config.mgmt_endpoint
c.storage_account_name = config.storage_acct_name
c.storage_access_key = config.storage_access_key
end
# 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)
provider = MsRestAzure::ApplicationTokenProvider.new(config.tenant_id, config.client_id, config.client_secret)
env[:azure_arm_service] = VagrantPlugins::Azure::Services::AzureResourceManager.new(provider, config.subscription_id)
end
@app.call(env)

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

@ -0,0 +1,19 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
module VagrantPlugins
module Azure
module Action
class IsCreated
def initialize(app, env)
@app = app
end
def call(env)
env[:result] = env[:machine].state.id != :not_created
@app.call(env)
end
end
end
end
end

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

@ -0,0 +1,19 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
module VagrantPlugins
module Azure
module Action
class IsStopped
def initialize(app, env)
@app = app
end
def call(env)
env[:result] = env[:machine].state.id != :stopped
@app.call(env)
end
end
end
end
end

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

@ -0,0 +1,19 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
module VagrantPlugins
module Azure
module Action
class MessageAlreadyCreated
def initialize(app, env)
@app = app
end
def call(env)
env[:ui].info(I18n.t('vagrant_azure.already_status', :status => 'created'))
@app.call(env)
end
end
end
end
end

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

@ -0,0 +1,19 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
module VagrantPlugins
module Azure
module Action
class MessageNotCreated
def initialize(app, env)
@app = app
end
def call(env)
env[:ui].info(I18n.t('vagrant_azure.not_created'))
@app.call(env)
end
end
end
end
end

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

@ -0,0 +1,19 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
module VagrantPlugins
module Azure
module Action
class MessageWillNotDestroy
def initialize(app, env)
@app = app
end
def call(env)
env[:ui].info(I18n.t('vagrant_azure.will_not_destroy', name: env[:machine].name))
@app.call(env)
end
end
end
end
end

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

@ -1,34 +0,0 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
require 'log4r'
module VagrantPlugins
module WinAzure
module Action
class OSType
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_azure::action::os_type')
end
def call(env)
unless env[:machine].config.vm.guest
env[:ui].info 'Determining OS Type By Image'
guest_os_type = env[:azure_vm_service].send(:get_image, env[:machine].provider_config.vm_image).os_type
env[:machine].config.vm.guest = guest_os_type && guest_os_type.downcase.to_sym
if env[:machine].config.vm.guest == :windows && env[:machine].config.vm.communicator.nil?
env[:machine].config.vm.communicator = :winrm
end
env[:ui].info "OS Type is #{guest_os_type}"
end
@app.call(env)
end
end
end
end
end

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

@ -1,28 +0,0 @@
module VagrantPlugins
module WinAzure
module Action
class PowerShellRun
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_azure::action::powershell_run_command')
end
def call(env)
if env[:machine].communicate.ready?
env[:machine].ui.detail("PowerShell Executing: #{env[:powershell_command]}")
env[:powershell_command_exit_status] = env[:machine].communicate.execute(env[:powershell_command]) do |type, stream|
if type == :stdout
env[:machine].ui.success(stream) unless (stream || '').chomp.empty?
else
env[:machine].ui.error(stream) unless (stream || '').chomp.empty?
end
end
end
@app.call(env)
end
end
end
end
end

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

@ -1,63 +0,0 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
require 'log4r'
require 'pathname'
require 'vagrant/util/subprocess'
require 'vagrant/util/platform'
module VagrantPlugins
module WinAzure
module Action
class Rdp
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_azure::action::rdp')
@rdp_file = 'machine.rdp'
end
def call(env)
if Vagrant::Util::Platform.windows?
generate_rdp_file env[:machine]
command = ['mstsc', @rdp_file]
Vagrant::Util::Subprocess.execute(*command)
elsif Vagrant::Util::Platform.darwin?
generate_rdp_file env[:machine]
command = ['open', @rdp_file]
result = Vagrant::Util::Subprocess.execute(*command)
if result.exit_code == 1
raise result.stderr
end
else
# TODO: Add support for RDP on *Nix systems
raise 'Unsupported operating system for RDP operation.'
end
@app.call(env)
end
def generate_rdp_file(machine)
File.delete(@rdp_file) if File.exists?(@rdp_file)
info = machine.provider.rdp_info
rdp_options = {
'drivestoredirect:s' => '*',
'username:s' => machine.provider_config.vm_user,
'prompt for credentials:i' => '1',
'full address:s' => "#{info[:host]}:#{info[:port]}"
}
file = File.open(@rdp_file, 'w')
rdp_options.each do |key, value|
file.puts "#{key}:#{value}"
end
file.close
end
end
end
end
end

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

@ -1,12 +1,10 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'log4r'
module VagrantPlugins
module WinAzure
module Azure
module Action
class ReadSSHInfo
def initialize(app, env, port = 22)

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

@ -1,12 +1,10 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'log4r'
module VagrantPlugins
module WinAzure
module Azure
module Action
class ReadState
def initialize(app, env)
@ -15,31 +13,48 @@ module VagrantPlugins
end
def call(env)
env[:machine_state_id] = read_state(env)
env[:machine_state_id] = read_state(env[:azure_arm_service], env[:machine])
@app.call(env)
end
def read_state(env)
env[:machine].id = "#{env[:machine].provider_config.vm_name}@#{env[:machine].provider_config.cloud_service_name}" unless env[:machine].id
# def read_state(azure, machine)
# env[:machine].id = "#{env[:machine].provider_config.vm_name}@#{env[:machine].provider_config.cloud_service_name}" unless env[:machine].id
#
# env[:machine].id =~ /@/
#
# env[:ui].info "Attempting to read state for #{$`} in #{$'}"
#
# vm = env[:azure_vm_service].get_virtual_machine($`, $')
#
# if vm.nil? || \
# !vm.instance_of?(Azure::VirtualMachineManagement::VirtualMachine) || \
# [ :DeletingVM ].include?(vm.status.to_sym)
# # Machine can't be found
# @logger.info 'Machine cannot be found'
# env[:machine].id = nil
# return :NotCreated
# end
#
# env[:ui].info "VM Status: #{vm.status.to_sym}"
# return vm.status.to_sym
# end
env[:machine].id =~ /@/
def read_state(azure, machine)
return :not_created if machine.id.nil?
env[:ui].info "Attempting to read state for #{$`} in #{$'}"
vm = env[:azure_vm_service].get_virtual_machine($`, $')
if vm.nil? || \
!vm.instance_of?(Azure::VirtualMachineManagement::VirtualMachine) || \
[ :DeletingVM ].include?(vm.status.to_sym)
# Machine can't be found
@logger.info 'Machine cannot be found'
env[:machine].id = nil
return :NotCreated
# Find the machine
config = machine.provider_config
server = azure.compute.virtual_machines.get(config.resource_group_name, machine.name, true).value!
if server.nil? || [:'shutting-down', :terminated].include?(server.state.to_sym)
# The machine can't be found
@logger.info('Machine not found or terminated, assuming it got destroyed.')
machine.id = nil
return :not_created
end
env[:ui].info "VM Status: #{vm.status.to_sym}"
return vm.status.to_sym
# Return the state
server.state.to_sym
end
end
end

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

@ -1,57 +0,0 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
require 'log4r'
module VagrantPlugins
module WinAzure
module Action
class ReadWinrmInfo
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_azure::action::read_winrm_info')
end
def call(env)
if env[:machine].config.vm.guest == :windows
env[:ui].detail 'Looking for WinRM'
env[:machine_winrm_info] = read_winrm_info(env[:azure_vm_service], env[:machine])
env[:ui].detail "Found public port #{env[:machine_winrm_info][:port]}"
end
@app.call(env)
end
def read_winrm_info(azure, machine)
return nil if machine.id.nil?
machine.id =~ /@/
vm = azure.get_virtual_machine($`, $')
if vm.nil? || !vm.instance_of?(Azure::VirtualMachineManagement::VirtualMachine)
# Machine cannot be found
@logger.info 'Machine not found. Assuming it was destroyed'
machine.id = nil
return nil
end
types = %w(PowerShell WinRm-Http)
endpoint = vm.tcp_endpoints.reject { |i| !types.include?(i[:name]) }.sort_by{ |i| i[:name] }.first
if endpoint
machine.config.winrm.host = "#{vm.cloud_service_name}.cloudapp.net"
machine.config.winrm.port = endpoint[:public_port]
if endpoint[:name] == types[0] # if it's PowerShell, then it's over https so use ssl (cert is self signed)
machine.config.winrm.ssl_peer_verification = false
machine.config.winrm.transport = :ssl
end
return {:host => "#{vm.cloud_service_name}.cloudapp.net", :port => endpoint[:public_port]}
end
nil
end
end
end
end
end

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

@ -1,12 +1,10 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'log4r'
module VagrantPlugins
module WinAzure
module Azure
module Action
class RestartVM
def initialize(app, env)

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

@ -1,17 +1,11 @@
#---------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'log4r'
require 'json'
require 'azure'
require 'openssl'
require 'vagrant/util/retryable'
module VagrantPlugins
module WinAzure
module Azure
module Action
class RunInstance
include Vagrant::Util::Retryable
@ -24,91 +18,8 @@ module VagrantPlugins
def call(env)
config = env[:machine].provider_config
# Add the mandatory parameters and options
params = {
vm_name: config.vm_name,
vm_user: config.vm_user,
image: config.vm_image
}
options = {
cloud_service_name: config.cloud_service_name
}
# Add the optional parameters and options if not nil
params[:password] = config.vm_password unless config.vm_password.nil?
params[:location] = config.vm_location unless config.vm_location.nil?
params[:affinity_group] = config.vm_affinity_group unless config.vm_affinity_group.nil?
options[:storage_account_name] = config.storage_acct_name unless config.storage_acct_name.nil?
options[:deployment_name] = config.deployment_name unless config.deployment_name.nil?
options[:tcp_endpoints] = config.tcp_endpoints unless config.tcp_endpoints.nil?
unless config.private_key_file.nil? && env[:machine].config.ssh.private_key_path.nil?
options[:private_key_file] = File.expand_path(config.private_key_file || env[:machine].config.ssh.private_key_path.first)
end
options[:ssh_port] = config.ssh_port unless config.ssh_port.nil?
options[:vm_size] = config.vm_size unless config.vm_size.nil?
options[:winrm_transport] = config.winrm_transport unless config.winrm_transport.nil?
options[:winrm_http_port] = config.winrm_http_port unless config.winrm_http_port.nil?
options[:winrm_https_port] = config.winrm_https_port unless config.winrm_https_port.nil?
options[:availability_set_name] = config.availability_set_name unless config.availability_set_name.nil?
options[:virtual_network_name] = config.vm_virtual_network_name unless config.vm_virtual_network_name.nil?
options[:subnet_name] = config.vm_subnet_name unless config.vm_subnet_name.nil?
if params[:password] && options[:private_key_file]
env[:ui].warn('You specified both a password and a private key file. The password will be used rather than ' +
'the private key. If you would like to use asymmetric key auth, do not specify a password.')
end
add_role = false
env[:ui].info(params.inspect)
env[:ui].info(options.inspect)
server = VagrantPlugins::WinAzure::CLOUD_SERVICE_SEMAPHORE.synchronize do
# Check if the cloud service exists and if yes, does it contain
# a deployment.
if config.cloud_service_name && !config.cloud_service_name.empty?
begin
cloud_service = Azure::BaseManagement::ManagementHttpRequest.new(
:get,
"/services/hostedservices/#{config.cloud_service_name}?embed-detail=true"
).call
deployments = cloud_service.css 'HostedService Deployments Deployment'
# Lets see if any deployments exist. Set add_role = true if yes.
# We're not worried about deployment slots, because the SDK has
# hard coded 'Production' as deployment slot and you can have only
# one deployment per deployment slot.
add_role = deployments.length == 1
rescue Exception => e
add_role = false
end
end
env[:ui].info("Add Role? - #{add_role}")
if add_role
env[:azure_vm_service].add_role(params.clone.merge(cloud_service_name: config.cloud_service_name), options)
else
env[:azure_vm_service].create_virtual_machine(params, options)
end
end
if server.nil?
raise Errors::CreateVMFailure
end
# The Ruby SDK returns any exception encountered on create virtual
# machine as a string.
if server.instance_of? String
raise Errors::ServerNotCreated, message: server
end
env[:machine].id = "#{server.vm_name}@#{server.cloud_service_name}"

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

@ -1,15 +1,13 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'log4r'
# require 'vagrant/util/retryable'
# Barebones basic implemenation. This a work in progress in very early stages
# Bare bones basic implementation. This a work in progress in very early stages
module VagrantPlugins
module WinAzure
module Azure
module Action
# This starts a stopped instance
class StartInstance
@ -23,7 +21,7 @@ module VagrantPlugins
env[:machine].id = "#{env[:machine].provider_config.vm_name}@#{env[:machine].provider_config.cloud_service_name}" unless env[:machine].id
env[:machine].id =~ /@/
VagrantPlugins::WinAzure::CLOUD_SERVICE_SEMAPHORE.synchronize do
VagrantPlugins::Azure::CLOUD_SERVICE_SEMAPHORE.synchronize do
env[:ui].info "Attempting to start '#{$`}' in '#{$'}'"
env[:azure_vm_service].start_virtual_machine($`, $')
end

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

@ -1,13 +1,11 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'log4r'
# Barebones basic implemenation. This a work in progress in very early stages
# Bare bones basic implementation. This a work in progress in very early stages
module VagrantPlugins
module WinAzure
module Azure
module Action
class StopInstance
@ -23,7 +21,7 @@ module VagrantPlugins
)
else
env[:machine].id =~ /@/
VagrantPlugins::WinAzure::CLOUD_SERVICE_SEMAPHORE.synchronize do
VagrantPlugins::Azure::CLOUD_SERVICE_SEMAPHORE.synchronize do
env[:ui].info(
I18n.t(
'vagrant_azure.stopping',

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

@ -1,64 +0,0 @@
# Copyright (c) 2014 Mitchell Hashimoto
# Under The MIT License (MIT)
#---------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
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].communicate.upload(hostpath, guestpath)
end
end
end
end
end
end
end

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

@ -1,11 +1,10 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache 2.0 License.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'log4r'
module VagrantPlugins
module WinAzure
module Azure
module Action
class TerminateInstance
def initialize(app, env)

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

@ -1,44 +0,0 @@
#---------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# 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

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

@ -1,47 +1,41 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'log4r'
require 'timeout'
module VagrantPlugins
module WinAzure
module Azure
module Action
class WaitForState
def initialize(app, env, state)
@app = app
@state = state
@logger = Log4r::Logger.new("vagrant_azure::action::wait_for_state")
# env[:result] will be false in case of timeout.
# @param [Symbol] state Target machine state.
# @param [Number] timeout Timeout in seconds.
# @param [Object] env vagrant environment
def initialize(app, env, state, timeout)
@app = app
@logger = Log4r::Logger.new('vagrant_azure::action::wait_for_state')
@state = state
@timeout = timeout
@env = env
end
def call(env)
env[:result] = true
if env[:machine].state.id == @state
@logger.info(
I18n.t('vagrant_azure.already_status', :status => @state)
)
@logger.info(I18n.t('vagrant_azure.already_status', :status => @state))
else
timeout = env[:machine].provider_config.state_read_timeout || env[:machine].config.vm.boot_timeout
env[:ui].info "Waiting for machine to reach state #{@state}"
@logger.info("Waiting for machine to reach state #{@state}")
begin
Timeout.timeout(timeout) do
Timeout.timeout(@timeout) do
until env[:machine].state.id == @state
sleep 30
sleep 2
end
end
env[:ui].success "Machine reached state #{@state}"
rescue Timeout::Error
env[:ui].error "Machine failed to reached state '#{@state}' in '#{timeout}' seconds."
env[:result] = false # couldn't reach state in time
end
end
@app.call(env)
end
end

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

@ -1,12 +0,0 @@
module VagrantPlugins
module WinAzure
module Cap
class WinRM
def self.winrm_info(machine)
env = machine.action('read_winrm_info')
env[:machine_winrm_info]
end
end
end
end
end

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

@ -1,43 +0,0 @@
module VagrantPlugins
module WinAzure
module Command
class PowerShell < Vagrant.plugin('2', :command)
def self.synopsis
'execute PowerShell command or script on remote machine'
end
def execute
options = {}
opts = OptionParser.new do |o|
o.banner = 'Usage: vagrant powershell [machine] -[c|s] [command|script file]'
o.separator ''
o.separator 'Options:'
o.separator ''
o.on('-c', '--command COMMAND', 'Execute a PowerShell command directly') do |c|
options[:command] = c
end
o.on('-s', '--script SCRIPT_FILE', 'Execute a PowerShell script directly') do |s|
raise Vagrant::Errors::CLIInvalidOptions, :help => "File #{s} can't be found. Does it exist?" unless File.exists?(s)
options[:command] = File.read(s)
end
end
argv = parse_options(opts)
if options.empty?
raise Vagrant::Errors::CLIInvalidOptions, :help => opts.help.chomp
end
with_target_vms(argv, single_target: true) do |vm|
@logger.debug("Executing single command on remote machine: #{options[:command]}")
vm.action(:powershell_run, powershell_command: options[:command])
end
0
end
end
end
end
end

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

@ -1,24 +0,0 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
module VagrantPlugins
module WinAzure
module Command
class RDP < Vagrant.plugin('2', :command)
def self.synopsis
'opens an RDP session for a vagrant machine'
end
def execute
with_target_vms do |vm|
vm.action(:rdp)
end
0
end
end
end
end
end

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

@ -1,120 +1,145 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'vagrant'
require 'azure'
require 'haikunator'
module VagrantPlugins
module WinAzure
module Azure
class Config < Vagrant.plugin('2', :config)
attr_accessor :mgmt_certificate
attr_accessor :mgmt_endpoint
# The Azure Active Directory Tenant ID -- ENV['AZURE_TENANT_ID']
#
# @return [String]
attr_accessor :tenant_id
# The Azure Active Directory Application Client ID -- ENV['AZURE_CLIENT_ID']
#
# @return [String]
attr_accessor :client_id
# The Azure Active Directory Application Client Secret -- ENV['AZURE_CLIENT_SECRET']
#
# @return [String]
attr_accessor :client_secret
# The Azure Subscription ID to use -- ENV['AZURE_SUBSCRIPTION_ID']
#
# @return [String]
attr_accessor :subscription_id
# (Optional) Name of the resource group to use. WARNING: the resource group will be removed upon destroy!!!
#
# @return [String]
attr_accessor :resource_group_name
# (Optional) Azure location to build the VM -- defaults to 'westus'
#
# @return [String]
attr_accessor :location
# (Optional) Name of the storage account to use -- ENV['AZURE_STORAGE_ACCOUNT']
#
# @return [String]
attr_accessor :storage_acct_name
attr_accessor :storage_access_key
# (Optional) Name of the virtual machine
#
# @return [String]
attr_accessor :vm_name
attr_accessor :vm_user
attr_accessor :vm_password
attr_accessor :vm_image
attr_accessor :vm_location
attr_accessor :vm_affinity_group
attr_accessor :vm_virtual_network_name
attr_accessor :vm_subnet_name
attr_accessor :cloud_service_name
attr_accessor :deployment_name
# (Optional) Password for the VM
#
# @return [String]
attr_accessor :vm_password
# (Optional) VM size to be used -- defaults to 'Standard_D1'. See: https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-sizes/
#
# @return [String]
attr_accessor :vm_size
# (Optional) Name of the virtual machine image urn to use -- defaults to 'canonical:ubuntuserver:16.04.0-DAILY-LTS:latest'. See: https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-cli-ps-findimage/
#
# @return [String]
attr_accessor :vm_image_urn
# (Optional) Name of the virtual network resource
#
# @return [String]
attr_accessor :virtual_network_name
# (Optional) Name of the virtual network subnet resource
#
# @return [String]
attr_accessor :subnet_name
# (Optional) TCP endpoints to open up for the VM
#
# @return [String]
attr_accessor :tcp_endpoints
# ssh_private_key and ssh_certificate_file is overly specific and probably should be deprecated in favor of
# private_key_file and certificate_file as they are in Azure ruby sdk.
# This is here to not break compatibility with previous versions.
attr_accessor :private_key_file
alias :ssh_private_key_file :private_key_file
alias :ssh_private_key_file= :private_key_file=
attr_accessor :ssh_port
attr_accessor :vm_size
attr_accessor :winrm_transport
attr_accessor :winrm_http_port
attr_accessor :winrm_https_port
# (Optional) Name of the virtual machine image
#
# @return [String]
attr_accessor :availability_set_name
attr_accessor :state_read_timeout
# (Optional) The timeout to wait for an instance to become ready -- default 120 seconds.
#
# @return [Fixnum]
attr_accessor :instance_ready_timeout
# (Optional) The interval to wait for checking an instance's state -- default 2 seconds.
#
# @return [Fixnum]
attr_accessor :instance_check_interval
# (Optional) The Azure Management API endpoint -- default 'https://management.azure.com' seconds -- ENV['AZURE_MANAGEMENT_ENDPOINT'].
#
# @return [String]
attr_accessor :management_endpoint
def initialize
@storage_acct_name = UNSET_VALUE
@storage_access_key = UNSET_VALUE
@mgmt_certificate = UNSET_VALUE
@mgmt_endpoint = UNSET_VALUE
@tenant_id = UNSET_VALUE
@client_id = UNSET_VALUE
@client_secret = UNSET_VALUE
@management_endpoint = UNSET_VALUE
@subscription_id = UNSET_VALUE
@resource_group_name = UNSET_VALUE
@location = UNSET_VALUE
@storage_acct_name = UNSET_VALUE
@vm_name = UNSET_VALUE
@vm_user = UNSET_VALUE
@vm_password = UNSET_VALUE
@vm_image = UNSET_VALUE
@vm_location = UNSET_VALUE
@vm_affinity_group = UNSET_VALUE
@vm_virtual_network_name = UNSET_VALUE
@vm_subnet_name = UNSET_VALUE
@cloud_service_name = UNSET_VALUE
@deployment_name = UNSET_VALUE
@vm_image_urn = UNSET_VALUE
@virtual_network_name = UNSET_VALUE
@subnet_name = UNSET_VALUE
@tcp_endpoints = UNSET_VALUE
@private_key_file = UNSET_VALUE
@ssh_port = UNSET_VALUE
@vm_size = UNSET_VALUE
@winrm_transport = UNSET_VALUE
@winrm_http_port = UNSET_VALUE
@winrm_https_port = UNSET_VALUE
@availability_set_name = UNSET_VALUE
@state_read_timeout = UNSET_VALUE
@instance_ready_timeout = UNSET_VALUE
@instance_check_interval = UNSET_VALUE
end
def finalize!
@storage_acct_name = ENV['AZURE_STORAGE_ACCOUNT'] if @storage_acct_name == UNSET_VALUE
@storage_access_key = ENV['AZURE_STORAGE_ACCESS_KEY'] if @storage_access_key == UNSET_VALUE
@mgmt_certificate = ENV['AZURE_MANAGEMENT_CERTIFICATE'] if @mgmt_certificate == UNSET_VALUE
@mgmt_endpoint = ENV['AZURE_MANAGEMENT_ENDPOINT'] if @mgmt_endpoint == UNSET_VALUE
@management_endpoint = (ENV['AZURE_MANAGEMENT_ENDPOINT'] || 'https://management.azure.com') if @management_endpoint == UNSET_VALUE
@subscription_id = ENV['AZURE_SUBSCRIPTION_ID'] if @subscription_id == UNSET_VALUE
@tenant_id = ENV['AZURE_TENANT_ID'] if @tenant_id == UNSET_VALUE
@client_id = ENV['AZURE_CLIENT_ID'] if @client_id == UNSET_VALUE
@client_secret = ENV['AZURE_CLIENT_SECRET'] if @client_secret == UNSET_VALUE
@vm_name = nil if @vm_name == UNSET_VALUE
@vm_user = 'vagrant' if @vm_user == UNSET_VALUE
@vm_name = Haikunator.haikunate(100) if @vm_name == UNSET_VALUE
@resource_group_name = Haikunator.haikunate(100) if @resource_group_name == UNSET_VALUE
@vm_password = nil if @vm_password == UNSET_VALUE
@vm_image = nil if @vm_image == UNSET_VALUE
@vm_location = 'West US' if @vm_location == UNSET_VALUE
@vm_affinity_group = nil if @vm_affinity_group == UNSET_VALUE
@vm_virtual_network_name = nil if @vm_virtual_network_name == UNSET_VALUE
@vm_subnet_name = nil if @vm_subnet_name == UNSET_VALUE
@cloud_service_name = nil if @cloud_service_name == UNSET_VALUE
@deployment_name = nil if @deployment_name == UNSET_VALUE
@vm_image_urn = 'canonical:ubuntuserver:16.04.0-DAILY-LTS:latest' if @vm_image_urn == UNSET_VALUE
@location = 'westus' if @location == UNSET_VALUE
@virtual_network_name = nil if @virtual_network_name == UNSET_VALUE
@subnet_name = nil if @subnet_name == UNSET_VALUE
@tcp_endpoints = nil if @tcp_endpoints == UNSET_VALUE
@private_key_file = nil if @private_key_file == UNSET_VALUE
@ssh_port = nil if @ssh_port == UNSET_VALUE
@vm_size = nil if @vm_size == UNSET_VALUE
@winrm_transport = nil if @winrm_transport == UNSET_VALUE
@winrm_http_port = nil if @winrm_http_port == UNSET_VALUE
@winrm_https_port = nil if @winrm_https_port == UNSET_VALUE
@vm_size = 'Standard_D1' if @vm_size == UNSET_VALUE
@availability_set_name = nil if @availability_set_name == UNSET_VALUE
@state_read_timeout = nil if @state_read_timeout == UNSET_VALUE
utils = Class.new.extend(Azure::Core::Utility)
# 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 = utils.random_string("#{@vm_name}storage").gsub(/[^0-9a-z ]/i, '').downcase[0..23]
end
if @cloud_service_name.nil? || @cloud_service_name.empty?
@cloud_service_name = utils.random_string("#{@vm_name}-service-")
end
@instance_ready_timeout = 120 if @instance_ready_timeout == UNSET_VALUE
@instance_check_interval = 2 if @instance_check_interval == UNSET_VALUE
end
def validate(machine)
@ -122,37 +147,8 @@ module VagrantPlugins
# Azure connection properties related validation.
errors << 'vagrant_azure.subscription_id.required' if @subscription_id.nil?
errors << 'vagrant_azure.mgmt_certificate.required' if @mgmt_certificate.nil?
errors << 'vagrant_azure.mgmt_endpoint.required' if @mgmt_endpoint.nil?
# Azure Virtual Machine related validation
errors << 'vagrant_azure.vm_name.required' if @vm_name.nil?
paths = machine.config.ssh.private_key_path
unless @vm_password || machine.config.ssh.password || @private_key_file || (paths && paths.count > 0)
errors << 'You must provide one of the following: ssh.private_key_path, azure.private_key_file, ssh.password or azure.vm_password.'
end
if (@private_key_file || (paths && paths.count > 0)) && (@vm_password || machine.config.ssh.password)
machine.config.ssh.password = @vm_password = nil
machine.ui.warn('You specified both private_key and password. Vagrant-Azure will only use the private_key in this case.')
end
if machine.config.ssh.password.nil? && @vm_password
machine.config.ssh.password = @vm_password
elsif machine.config.ssh.password && @vm_password.nil?
@vm_password = machine.config.ssh.password
end
if machine.config.ssh.private_key_path.nil? && @private_key_file
machine.config.ssh.private_key_path = [File.expand_path(@private_key_file)]
elsif machine.config.ssh.private_key_path && @private_key_file.nil?
@private_key_file = File.expand_path(paths.first)
end
if @vm_virtual_network_name.nil? && @vm_subnet_name
errors << 'You specified a vm_subnet_name without a vm_virtual_network_name'
end
errors << 'vagrant_azure.mgmt_endpoint.required' if @management_endpoint.nil?
errors << 'vagrant_azure.auth.required' if @tenant_id.nil? || @client_secret.nil? || @client_id.nil?
{ 'Microsoft Azure Provider' => errors }
end

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

@ -1,48 +0,0 @@
#---------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
require 'json'
require "#{Vagrant::source_root}/plugins/providers/hyperv/driver"
module VagrantPlugins
module WinAzure
class Driver < VagrantPlugins::HyperV::Driver
def initialize(machine)
@id = machine.id
@machine = machine
end
def ssh_info
@ssh_info ||= @machine.provider.winrm_info
@ssh_info[:username] ||= @machine.config.ssh.username
@ssh_info[:password] ||= @machine.config.ssh.password
@ssh_info
end
def remote_credentials
@remote_credentials ||= {
guest_ip: ssh_info[:host],
guest_port: ssh_info[:port],
username: ssh_info[:username],
password: ssh_info[:password]
}
end
def run_remote_ps(command, &block)
@machine.communicate.execute(command) do |*args|
block.call(args) unless block.nil?
end
end
def upload(from, to)
@machine.communicate.upload(from, to)
end
def check_winrm
@machine.communicate.ready?
end
end
end
end

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

@ -1,25 +1,23 @@
#-------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
module VagrantPlugins
module WinAzure
module Azure
module Errors
class WinAzureError < Vagrant::Errors::VagrantError
error_namespace("vagrant_azure.errors")
class AzureError < Vagrant::Errors::VagrantError
error_namespace('vagrant_azure.errors')
end
class WinRMNotReady < WinAzureError
class WinRMNotReady < AzureError
error_key(:win_rm_not_ready)
end
class ServerNotCreated < WinAzureError
class ServerNotCreated < AzureError
error_key(:server_not_created)
end
class CreateVMFailure < WinAzureError
class CreateVMFailure < AzureError
error_key(:create_vm_failure)
end

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

@ -1,12 +0,0 @@
VagrantPlugins::CommunicatorWinRM::WinRMShell.class_eval do
def endpoint_options
{user: @username,
pass: @password,
host: @host,
port: @port,
basic_auth_only: false,
no_ssl_peer_verification: !@config.ssl_peer_verification,
disable_sspi: true
}
end
end

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

@ -1,8 +1,6 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
begin
require 'vagrant'
rescue LoadError
@ -16,12 +14,12 @@ if Vagrant::VERSION < '1.6.0'
end
module VagrantPlugins
module WinAzure
module Azure
class Plugin < Vagrant.plugin('2')
name 'azure'
name 'Azure'
description <<-DESC
This plugin installs a provider that allows Vagrant to manage
machines in Windows Azure.
machines in Microsoft Azure.
DESC
config(:azure, :provider) do
@ -33,38 +31,16 @@ module VagrantPlugins
# Setup logging and i18n
setup_logging
setup_i18n
apply_patches
# Return the provider
require_relative 'provider'
Provider
end
provider_capability(:azure, :winrm_info) do
require_relative 'capabilities/winrm'
VagrantPlugins::WinAzure::Cap::WinRM
end
command 'powershell' do
require_relative 'command/powershell'
VagrantPlugins::WinAzure::Command::PowerShell
end
command 'rdp' do
require_relative 'command/rdp'
VagrantPlugins::WinAzure::Command::RDP
end
def self.apply_patches
lib_path = Pathname.new(File.expand_path('../../vagrant-azure', __FILE__))
Vagrant.plugin('2').manager.communicators[:winrm]
require lib_path.join('monkey_patch/winrm')
end
def self.setup_i18n
I18n.load_path << File.expand_path(
'locales/en.yml',
WinAzure.source_root
Azure.source_root
)
I18n.load_path << File.expand_path(
'templates/locales/en.yml',
@ -98,7 +74,7 @@ module VagrantPlugins
# Set the logging level on all "vagrant" namespaced logs as long as
# we have a valid level
if level
logger = Log4r::Logger.new("vagrant_azure")
logger = Log4r::Logger.new('vagrant_azure')
logger.outputters = Log4r::Outputter.stderr
logger.level = level
logger = nil

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

@ -1,24 +1,15 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'log4r'
require 'vagrant'
module VagrantPlugins
module WinAzure
module Azure
class Provider < Vagrant.plugin('2', :provider)
attr_reader :driver
def initialize(machine)
@machine = machine
# Load the driver
machine_id_changed
@machine.config.winrm.password = @machine.provider_config.vm_password || @machine.provider_config.vm_user
@machine.config.winrm.username = @machine.provider_config.vm_user
end
def action(name)
@ -30,10 +21,6 @@ module VagrantPlugins
nil
end
def machine_id_changed
@driver = Driver.new(@machine)
end
def ssh_info
# Run a custom action called "read_ssh_info" which does what it
# says and puts the resulting SSH info into the `:machine_ssh_info`
@ -42,24 +29,15 @@ module VagrantPlugins
env[:machine_ssh_info]
end
def rdp_info
env = @machine.action('read_rdp_info')
env[:machine_ssh_info]
end
def winrm_info
env = @machine.action('read_winrm_info')
env[:machine_winrm_info]
end
def state
# Run a custom action we define called "read_state" which does what it
# says. It puts the state in the `:machine_state_id` key in the env
env = @machine.action('read_state')
state_id = env[:machine_state_id]
short = "Machine's current state is #{state_id}"
long = ""
# Get the short and long description
short = I18n.t("vagrant_azure.states.short_#{state_id}")
long = I18n.t("vagrant_azure.states.long_#{state_id}")
# Return the MachineState object
Vagrant::MachineState.new(state_id, short, long)

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

@ -0,0 +1,80 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'azure_mgmt_resources'
require 'azure_mgmt_compute'
require 'azure_mgmt_network'
require 'azure_mgmt_storage'
module VagrantPlugins
module Azure
module Services
class AzureResourceManager
TENANT_ID_NAME = 'AZURE_TENANT_ID'
CLIENT_ID_NAME = 'AZURE_CLIENT_ID'
CLIENT_SECRET_NAME = 'AZURE_CLIENT_SECRET'
# AzureResourceManager provides access to the Azure Resource Manager APIs
# @param [MsRest::TokenProvider] token_provider object used to procure an authentication token from Azure Active
# Directory
# @param [String] subscription_id
# @param [String] base_url
def initialize(token_provider, subscription_id, base_url = nil)
@token_provider = if token_provider.nil? || !token_provider.is_a?(MsRest::TokenProvider)
if ENV[TENANT_ID_NAME].nil? || ENV[CLIENT_ID_NAME].nil? || ENV[CLIENT_SECRET_NAME].nil?
raise ArgumentError "Either set #{TENANT_ID_NAME}, #{CLIENT_ID_NAME} or #{CLIENT_SECRET_NAME} in your environment, or pass in a MsRest::TokenProvider"
else
MsRestAzure::ApplicationTokenProvider.new(
ENV[TENANT_ID_NAME],
ENV[CLIENT_ID_NAME],
ENV[CLIENT_SECRET_NAME])
end
else
token_provider
end
@credential = MsRest::TokenCredentials.new(token_provider)
@base_url = base_url
@subscription_id = subscription_id
end
# Azure Resource Manager Compute API Client
# @return [Azure::ARM::Compute::ComputeManagementClient]
def compute
build(::Azure::ARM::Compute::ComputeManagementClient)
end
# Azure Resource Manager Generic Resource API Client
# @return [Azure::ARM::Resources::ResourceManagementClient]
def resources
build(::Azure::ARM::Resources::ResourceManagementClient)
end
# Azure Resource Manager Network API Client
# @return [Azure::ARM::Network::NetworkManagementClient]
def network
build(::Azure::ARM::Network::NetworkManagementClient)
end
# Azure Resource Manager Storage API Client
# @return [Azure::ARM::Storage::StorageManagementClient]
def storage
build(::Azure::ARM::Storage::StorageManagementClient)
end
private
def build(clazz)
instance = clazz.new(*client_params)
instance.subscription_id = @subscription_id
instance
end
def client_params
[@credential, @base_url].reject{ |i| i.nil? }
end
end
end
end
end

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

@ -1,11 +1,9 @@
#--------------------------------------------------------------------------
# Copyright (c) Microsoft Open Technologies, Inc.
# All Rights Reserved. Licensed under the Apache License, Version 2.0.
# See License.txt in the project root for license information.
#--------------------------------------------------------------------------
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
module VagrantPlugins
module WinAzure
VERSION = '1.3.1'
module Azure
VERSION = '2.0.0'
end
end

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

@ -35,3 +35,40 @@ en:
Server not created. Error is: %{message}
create_vm_failure: |-
There was some error in creating the VM.
subscription_id:
required: |-
You must provide an Azure Subscription Id either through ENV['AZURE_SUBSCRIPTION_ID'] or via Vagrantfile.
mgmt_endpoint:
required: |-
You must provide a non-nil Azure Management Endpoint either through ENV['AZURE_MANAGEMENT_ENDPOINT'] or via Vagrantfile.
auth:
required: |-
You must provide Azure Active Directory Tenant ID, Application Client ID and Application Client Secret via ENV or Vagrantfile.
states:
short_not_created: |-
not created
long_not_created: |-
The Azure instance is not created. Run `vagrant up` to create it.
short_stopped: |-
stopped
long_stopped: |-
The Azure instance is stopped. Run `vagrant up` to start it.
short_stopping: |-
stopping
long_stopping: |-
The Azure instance is stopping. Wait until is completely stopped to
run `vagrant up` and start it.
short_pending: |-
pending
long_pending: |-
The Azure instance is pending a start (i.e. this is a transition state).
short_running: |-
running
long_running: |-
The Azure instance is running. To stop this machine, you can run
`vagrant halt`. To destroy the machine, you can run `vagrant destroy`.
short_pending: |-
pending
long_pending: |-
The Azure instance is still being initialized. To destroy this machine,
you can run `vagrant destroy`.

40
spec/spec_helper.rb Normal file
Просмотреть файл

@ -0,0 +1,40 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'vagrant-azure'
if ENV['COVERAGE'] || ENV['CI'] || ENV['TRAVIS']
require 'simplecov'
require 'coveralls'
if ENV['TRAVIS']
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
SimpleCov::Formatter::HTMLFormatter,
Coveralls::SimpleCov::Formatter
]
else
SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter
end
SimpleCov.start do
project_name 'vagrant-azure'
add_filter '/build-tests/'
add_filter '/coverage/'
add_filter '/locales/'
add_filter '/templates/'
add_filter '/doc/'
add_filter '/example_box/'
add_filter '/pkg/'
add_filter '/spec/'
add_filter '/tasks/'
add_filter '/yard-template/'
add_filter '/yardoc/'
end
end
# import all the support files
Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require File.expand_path(f) }
RSpec.configure do |config|
config.order = 'random'
end

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

@ -0,0 +1,18 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'vagrant'
require 'vagrant-azure/config'
module VagrantPlugins
module Azure
describe Config do
it 'should config' do
end
end
end
end

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

@ -0,0 +1,19 @@
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
require 'vagrant-azure/services/azure_resource_manager'
module VagrantPlugins
module Azure
module Services
describe AzureResourceManager do
it 'should be hello world' do
end
end
end
end
end

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

@ -0,0 +1,249 @@
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUserName": {
"type": "string",
"defaultValue": "vagrant",
"metadata": {
"description": "User name for the Virtual Machine."
}
},
"sshKeyData": {
"type": "string",
"metadata": {
"description": "SSH rsa public key file as a string."
}
},
"dnsLabelPrefix": {
"type": "string",
"metadata": {
"description": "Unique DNS Name for the Public IP used to access the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_D1",
"metadata": {
"description": "Size of the VM"
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name of the VM"
}
},
"imagePublisher": {
"type": "string",
"defaultValue": "canonical",
"metadata": {
"description": "Name of the image publisher"
}
},
"imageOffer": {
"type": "string",
"defaultValue": "ubuntuserver",
"metadata": {
"description": "Name of the image offer"
}
},
"imageSku": {
"type": "string",
"defaultValue": "16.04.0-DAILY-LTS",
"metadata": {
"description": "Name of the image sku"
}
},
"subnet1Name": {
"type": "string",
"defaultValue": "vagrant-subnet-1",
"metadata": {
"description": "Name of the subnet"
}
},
"virtualNetworkName": {
"type": "string",
"defaultValue": "vagrantVNET",
"metadata": {
"description": "Name of the virtual network"
}
}
},
"variables": {
"storageAccountName": "[concat(uniquestring(resourceGroup().id), 'sasshvm')]",
"location": "[resourceGroup().location]",
"osDiskName": "osDisk1",
"addressPrefix": "10.0.0.0/16",
"subnet1Prefix": "10.0.0.0/24",
"vmStorageAccountContainerName": "vagrant-vhds",
"nicName": "SshNIC",
"publicIPAddressName": "vagrantPublicIP",
"publicIPAddressType": "Dynamic",
"storageAccountType": "Standard_LRS",
"networkSecurityGroupName": "vagrantNetworkSecurityGroup1",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]",
"subnet1Ref": "[concat(variables('vnetID'),'/subnets/',parameters('subnet1Name'))]",
"apiVersion": "2015-06-15"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"apiVersion": "[variables('apiVersion')]",
"location": "[variables('location')]",
"properties": {
"accountType": "[variables('storageAccountType')]"
}
},
{
"apiVersion": "[variables('apiVersion')]",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('networkSecurityGroupName')]",
"location": "[variables('location')]",
"properties": {
"securityRules": [
{
"name": "ssh_rule",
"properties": {
"description": "Locks inbound down to ssh default port 22.",
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 123,
"direction": "Inbound"
}
}
]
}
},
{
"apiVersion": "[variables('apiVersion')]",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[variables('location')]",
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
}
}
},
{
"apiVersion": "[variables('apiVersion')]",
"type": "Microsoft.Network/virtualNetworks",
"name": "[parameters('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[parameters('subnet1Name')]",
"properties": {
"addressPrefix": "[variables('subnet1Prefix')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}
}
}
]
}
},
{
"apiVersion": "[variables('apiVersion')]",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
"[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]"
},
"subnet": {
"id": "[variables('subnet1Ref')]"
}
}
}
]
}
},
{
"apiVersion": "[variables('apiVersion')]",
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('vmName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"osProfile": {
"computerName": "[parameters('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"linuxConfiguration": {
"disablePasswordAuthentication": "true",
"ssh": {
"publicKeys": [
{
"path": "[variables('sshKeyPath')]",
"keyData": "[parameters('sshKeyData')]"
}
]
}
}
},
"storageProfile": {
"imageReference": {
"publisher": "[parameters('imagePublisher')]",
"offer": "[parameters('imageOffer')]",
"sku": "[parameters('imageSku')]",
"version": "latest"
},
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', variables('osDiskName'),'.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": "true",
"storageUri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net')]"
}
}
}
}
]
}

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

@ -1,27 +1,32 @@
# coding: utf-8
# encoding: utf-8
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License in the project root for license information.
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'vagrant-azure/version'
Gem::Specification.new do |s|
s.name = 'vagrant-azure'
s.version = VagrantPlugins::WinAzure::VERSION
s.authors = %w(MSOpenTech Azure)
s.description = 'Enable Vagrant to manage machines in Azure.'
s.summary = 'Enable Vagrant to manage Windows and Linux machines in Azure.'
s.homepage = 'https://github.com/MSOpenTech/vagrant-azure'
s.license = 'Apache 2.0'
s.version = VagrantPlugins::Azure::VERSION
s.authors = %w(Azure)
s.description = 'Enable Vagrant to manage machines in Microsoft Azure.'
s.summary = 'Enable Vagrant to manage Windows and Linux machines in Microsoft Azure.'
s.homepage = 'https://github.com/azure/vagrant-azure'
s.license = 'MIT'
s.require_paths = ['lib']
s.files = `git ls-files`.split("\n")
s.bindir = 'bin'
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
s.add_runtime_dependency 'azure', '0.7.1'
s.add_runtime_dependency 'httpclient', '2.4.0'
s.add_runtime_dependency 'azure_mgmt_resources', '~>0.2.1'
s.add_runtime_dependency 'azure_mgmt_compute', '~>0.2.1'
s.add_runtime_dependency 'azure_mgmt_network', '~>0.2.1'
s.add_runtime_dependency 'azure_mgmt_storage', '~>0.2.1'
s.add_runtime_dependency 'haikunator', '~>1.1'
s.add_development_dependency 'bundler', '~> 1.3'
s.add_development_dependency 'rake'
s.add_development_dependency 'minitest'
s.add_development_dependency 'minitest-reporters'
s.add_development_dependency 'mocha'
s.add_development_dependency 'bundler', '~>1.9'
s.add_development_dependency 'rake', '~>11.1'
s.add_development_dependency 'rspec', '~>3.4'
s.add_development_dependency 'simplecov', '~>0.11.2'
s.add_development_dependency 'coveralls', '~>0.8'
end