Merge pull request #113 from devigned/feature/arm

ARM version of Vagrant-Azure (initial)
This commit is contained in:
David Justice 2016-03-29 13:55:26 -07:00
Родитель 1c0916c19f 9411b2da4d
Коммит 845d43c093
49 изменённых файлов: 1292 добавлений и 1075 удалений

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'

29
example_box/Vagrantfile поставляемый
Просмотреть файл

@ -10,34 +10,5 @@ Vagrant.configure('2') do |config|
config.vm.box = 'azure'
config.vm.provider :azure do |azure, override|
# Mandatory Settings
azure.mgmt_certificate = '/Users/alexvinyar/Documents/Projects/Azure/managementCertificate.pem'
azure.mgmt_endpoint = 'https://management.core.windows.net'
azure.subscription_id = '12345678-abcd-1234-5678-abcdefghijk'
# azure.vm_image = 'b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04_1-LTS-amd64-server-20140927-en-us-30GB'
azure.vm_image = 'a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-20150916-en.us-127GB.vhd'
azure.vm_name = 'martymcfly1' # max 15 characters. contains letters, number and hyphens. can start with letters and can end with letters and numbers
# vm_password is optional when specifying the private_key_file with Linux VMs
# When building a Windows VM and using WinRM this setting is used to authenticate via WinRM (PowerShell Remoting)
azure.vm_password = 'Not##RealPass' # min 8 characters. should contain a lower case letter, an uppercase letter, a number and a special character
azure.vm_size = 'Small'
# # Optional Settings
azure.storage_acct_name = 'martymcfly' # optional. A new one will be generated if not provided.
# azure.vm_user = 'PROVIDE A USERNAME' # defaults to 'vagrant' if not provided
# azure.cloud_service_name = 'PROVIDE A NAME FOR YOUR CLOUD SERVICE' # same as vm_name. leave blank to auto-generate
# azure.deployment_name = 'PROVIDE A NAME FOR YOUR DEPLOYMENT' # defaults to cloud_service_name
# azure.vm_location = 'PROVIDE A LOCATION FOR VM' # e.g., West US
# # Optional *Nix Settings
# azure.ssh_port = 'A VALID PUBLIC PORT' # defaults to 22
# azure.private_key_file = 'Path to your ssh private key file (~/.ssh/id_rsa) to use for passwordless auth. If the id_rsa file is password protected, you will be prompted for the password.'
# # Optional Windows Settings
azure.winrm_transport = ['http', 'https'] # this will open up winrm ports on both http (5985) and http (5986) ports
# azure.winrm_https_port = 'A VALID PUBLIC PORT' # customize the winrm https port, instead of 5986
# azure.winrm_http_port = 'A VALID PUBLIC PORT' # customize the winrm http port, insted of 5985
azure.tcp_endpoints = '3389:53389' # opens the Remote Desktop internal port that listens on public port 53389. Without this, you cannot RDP to a Windows VM.
end
end

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

@ -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,14 +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-azure/util/machine_id_helper'
module VagrantPlugins
module WinAzure
module Azure
module Action
class ReadSSHInfo
include VagrantPlugins::Azure::Util::MachineIdHelper
def initialize(app, env, port = 22)
@app = app
@port = port
@ -16,37 +17,16 @@ module VagrantPlugins
end
def call(env)
env[:ui].detail "Looking for local port #{@port}"
env[:machine_ssh_info] = read_ssh_info(
env[:azure_vm_service],
env[:machine]
)
env[:ui].detail "Found port mapping #{env[:machine_ssh_info][:port]} --> #{@port}"
env[:machine_ssh_info] = read_ssh_info(env[:azure_arm_service], env)
@app.call(env)
end
def read_ssh_info(azure, machine)
return nil if machine.id.nil?
machine.id =~ /@/
vm = azure.get_virtual_machine($`, $')
def read_ssh_info(azure, env)
return nil if env[:machine].id.nil?
parsed = parse_machine_id(env[:machine].id)
public_ip = azure.network.public_ipaddresses.get(parsed[:group], "#{parsed[:name]}-vagrantPublicIP").value!.body
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
vm.tcp_endpoints.each do |endpoint|
if endpoint[:local_port] == "#{@port}"
return { :host => "#{vm.cloud_service_name}.cloudapp.net", :port => endpoint[:public_port] }
end
end
return nil
{:host => public_ip.properties.dns_settings.fqdn, :port => 22}
end
end
end

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

@ -1,46 +1,48 @@
#--------------------------------------------------------------------------
# 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-azure/util/vm_status_translator'
require 'vagrant-azure/util/machine_id_helper'
module VagrantPlugins
module WinAzure
module Azure
module Action
class ReadState
include VagrantPlugins::Azure::Util::VMStatusTranslator
include VagrantPlugins::Azure::Util::MachineIdHelper
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_azure::action::read_state')
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)
return :not_created if machine.id.nil?
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
# Find the machine
parsed = parse_machine_id(machine.id)
vm = nil
begin
vm = azure.compute.virtual_machines.get(parsed[:group], parsed[:name], 'instanceView').value!.body
rescue MsRestAzure::AzureOperationError => ex
if vm.nil? || tearing_down?(vm.properties.instance_view.statuses)
# The machine can't be found
@logger.info('Machine not found or terminated, assuming it got destroyed.')
machine.id = nil
return :not_created
end
end
env[:ui].info "VM Status: #{vm.status.to_sym}"
return vm.status.to_sym
# Return the state
power_state(vm.properties.instance_view.statuses)
end
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,25 +1,25 @@
#--------------------------------------------------------------------------
# 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-azure/util/machine_id_helper'
module VagrantPlugins
module WinAzure
module Azure
module Action
class RestartVM
include VagrantPlugins::Azure::Util::MachineIdHelper
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_azure::action::restart_vm')
end
def call(env)
env[:machine].id =~ /@/
env[:ui].info "Restarting #{$`} in #{$'}"
env[:azure_vm_service].restart_virtual_machine($`, $')
parsed = parse_machine_id(env[:machine].id)
env[:ui].info(I18n.t('vagrant_azure.restarting', parsed))
env[:azure_arm_service].compute.virtual_machines.restart(parsed[:group], parsed[:name])
env[:ui].info(I18n.t('vagrant_azure.restarted', parsed))
@app.call(env)
end
end

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

@ -1,20 +1,20 @@
#---------------------------------------------------------------------------
# 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'
require 'azure_mgmt_resources'
require 'vagrant/util/template_renderer'
require 'vagrant-azure/util/timer'
require 'vagrant-azure/util/machine_id_helper'
require 'haikunator'
module VagrantPlugins
module WinAzure
module Azure
module Action
class RunInstance
include Vagrant::Util::Retryable
include VagrantPlugins::Azure::Util::MachineIdHelper
def initialize(app, env)
@app = app
@ -22,98 +22,182 @@ module VagrantPlugins
end
def call(env)
config = env[:machine].provider_config
# Initialize metrics if they haven't been
env[:metrics] ||= {}
# Add the mandatory parameters and options
params = {
vm_name: config.vm_name,
vm_user: config.vm_user,
image: config.vm_image
machine = env[:machine]
# Get the configs
config = machine.provider_config
endpoint = config.endpoint
resource_group_name = config.resource_group_name
location = config.location
vm_name = config.vm_name
vm_password = config.vm_password
vm_size = config.vm_size
vm_image_urn = config.vm_image_urn
virtual_network_name = config.virtual_network_name
subnet_name = config.subnet_name
tcp_endpoints = config.tcp_endpoints
availability_set_name = config.availability_set_name
# Launch!
env[:ui].info(I18n.t('vagrant_azure.launching_instance'))
env[:ui].info(" -- Management Endpoint: #{endpoint}")
env[:ui].info(" -- Subscription Id: #{config.subscription_id}")
env[:ui].info(" -- Resource Group Name: #{resource_group_name}")
env[:ui].info(" -- Location: #{location}")
env[:ui].info(" -- VM Name: #{vm_name}")
env[:ui].info(" -- VM Size: #{vm_size}")
env[:ui].info(" -- Image URN: #{vm_image_urn}")
env[:ui].info(" -- Virtual Network Name: #{virtual_network_name}") if virtual_network_name
env[:ui].info(" -- Subnet Name: #{subnet_name}") if subnet_name
env[:ui].info(" -- TCP Endpoints: #{tcp_endpoints}") if tcp_endpoints
env[:ui].info(" -- Availability Set Name: #{availability_set_name}") if availability_set_name
image_publisher, image_offer, image_sku, image_version = vm_image_urn.split(':')
azure = env[:azure_arm_service]
image_details = nil
env[:metrics]['get_image_details'] = Util::Timer.time do
image_details = get_image_details(azure, location, image_publisher, image_offer, image_sku, image_version)
end
@logger.info("Time to fetch os image details: #{env[:metrics]['get_image_details']}")
deployment_params = {
dnsLabelPrefix: Haikunator.haikunate(100),
vmSize: vm_size,
vmName: vm_name,
imagePublisher: image_publisher,
imageOffer: image_offer,
imageSku: image_sku,
imageVersion: image_version,
subnetName: subnet_name,
virtualNetworkName: virtual_network_name
}
options = {
cloud_service_name: config.cloud_service_name
if get_image_os(image_details) != 'Windows'
private_key_paths = machine.config.ssh.private_key_path
if private_key_paths.empty?
raise I18n.t('vagrant_azure.private_key_not_specified')
end
paths_to_pub = private_key_paths.map{ |k| File.expand_path( k + '.pub') }.select{ |p| File.exists?(p) }
raise I18n.t('vagrant_azure.public_key_path_private_key', private_key_paths.join(', ')) if paths_to_pub.empty?
deployment_params.merge!(sshKeyData: File.read(paths_to_pub.first))
end
template_params = {
operating_system: get_image_os(image_details)
}
# 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)
env[:ui].info(" -- Create or Update of Resource Group: #{resource_group_name}")
env[:metrics]['put_resource_group'] = Util::Timer.time do
put_resource_group(azure, resource_group_name, location)
end
@logger.info("Time to create resource group: #{env[:metrics]['put_resource_group']}")
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?
deployment_params = build_deployment_params(template_params, deployment_params.reject{|_,v| v.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.')
env[:ui].info('Starting deployment')
env[:metrics]['deployment_time'] = Util::Timer.time do
put_deployment(azure, resource_group_name, deployment_params)
end
env[:ui].info('Finished deploying')
add_role = false
# Immediately save the ID since it is created at this point.
env[:machine].id = serialize_machine_id(resource_group_name, vm_name, location)
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
@logger.info("Time to deploy: #{env[:metrics]['deployment_time']}")
unless env[:interrupted]
env[:metrics]['instance_ssh_time'] = Util::Timer.time do
# Wait for SSH to be ready.
env[:ui].info(I18n.t('vagrant_azure.waiting_for_ssh'))
network_ready_retries = 0
network_ready_retries_max = 10
while true
break if env[:interrupted]
begin
break if env[:machine].communicate.ready?
rescue Exception => e
if network_ready_retries < network_ready_retries_max
network_ready_retries += 1
@logger.warn(I18n.t('vagrant_azure.waiting_for_ssh, retrying'))
else
raise e
end
end
sleep 2
end
end
env[:ui].info("Add Role? - #{add_role}")
@logger.info("Time for SSH ready: #{env[:metrics]['instance_ssh_time']}")
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
# Ready and booted!
env[:ui].info(I18n.t('vagrant_azure.ready'))
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}"
# Terminate the instance if we were interrupted
terminate(env) if env[:interrupted]
@app.call(env)
end
def get_image_os(image_details)
image_details.properties.os_disk_image.operating_system
end
def get_image_details(azure, location, publisher, offer, sku, version)
if version == 'latest'
latest = azure.compute.virtual_machine_images.list(location, publisher, offer, sku).value!.body.last
azure.compute.virtual_machine_images.get(location, publisher, offer, sku, latest.name).value!.body
else
azure.compute.virtual_machine_images.get(location, publisher, offer, sku, version).value!.body
end
end
def put_deployment(azure, rg_name, params)
azure.resources.deployments.create_or_update(rg_name, 'vagrant', params).value!.body
end
def put_resource_group(azure, name, location)
params = ::Azure::ARM::Resources::Models::ResourceGroup.new.tap do |rg|
rg.location = location
end
azure.resources.resource_groups.create_or_update(name, params).value!.body
end
# This method generates the deployment template
def render_deployment_template(options)
Vagrant::Util::TemplateRenderer.render('arm/deployment.json', options.merge(template_root: template_root))
end
def build_deployment_params(template_params, deployment_params)
params = ::Azure::ARM::Resources::Models::Deployment.new
params.properties = ::Azure::ARM::Resources::Models::DeploymentProperties.new
params.properties.template = JSON.parse(render_deployment_template(template_params))
params.properties.mode = ::Azure::ARM::Resources::Models::DeploymentMode::Incremental
params.properties.parameters = build_parameters(deployment_params)
params
end
def build_parameters(options)
Hash[*options.map{ |k, v| [k, {value: v}] }.flatten]
end
# Used to find the base location of aws-vagrant templates
def template_root
Azure.source_root.join('templates')
end
def terminate(env)
destroy_env = env.dup
destroy_env.delete(:interrupted)
destroy_env[:config_validate] = false
destroy_env[:force_confirm_destroy] = true
env[:action_runner].run(Action.action_destroy, destroy_env)
end
end
end
end

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

@ -1,32 +1,51 @@
#--------------------------------------------------------------------------
# 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-azure/util/machine_id_helper'
require 'vagrant-azure/util/vm_status_translator'
require 'vagrant/util/retryable'
require 'vagrant-azure/util/timer'
require 'vagrant-azure/util/vm_await'
# require 'vagrant/util/retryable'
# Barebones basic implemenation. This a work in progress in very early stages
module VagrantPlugins
module WinAzure
module Azure
module Action
# This starts a stopped instance
class StartInstance
include VagrantPlugins::Azure::Util::MachineIdHelper
include VagrantPlugins::Azure::Util::VMStatusTranslator
include VagrantPlugins::Azure::Util::VMAwait
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_azure:action::start_instance')
@logger = Log4r::Logger.new('vagrant_azure::action::start_instance')
end
def call(env)
env[:machine].id = "#{env[:machine].provider_config.vm_name}@#{env[:machine].provider_config.cloud_service_name}" unless env[:machine].id
env[:machine].id =~ /@/
env[:metrics] ||= {}
VagrantPlugins::WinAzure::CLOUD_SERVICE_SEMAPHORE.synchronize do
env[:ui].info "Attempting to start '#{$`}' in '#{$'}'"
env[:azure_vm_service].start_virtual_machine($`, $')
parsed = parse_machine_id(env[:machine].id)
azure = env[:azure_arm_service]
env[:ui].info(I18n.t('vagrant_azure.starting', parsed))
azure.compute.virtual_machines.start(parsed[:group], parsed[:name])
# Wait for the instance to be ready first
env[:metrics]['instance_ready_time'] = Util::Timer.time do
env[:ui].info(I18n.t('vagrant_azure.waiting_for_ready'))
task = await_true(env) do |vm|
running?(vm.properties.instance_view.statuses)
end
if task.value
env[:ui].info(I18n.t('vagrant_azure.started', parsed))
else
raise I18n.t('vagrant_azure.errors.failed_starting', parsed) unless env[:interrupted]
end
end
@app.call(env)
end
end

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

@ -1,15 +1,19 @@
#--------------------------------------------------------------------------
# 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-azure/util/machine_id_helper'
require 'vagrant-azure/util/vm_await'
require 'vagrant-azure/util/vm_status_translator'
require 'vagrant-azure/util/timer'
# Barebones basic implemenation. This a work in progress in very early stages
module VagrantPlugins
module WinAzure
module Azure
module Action
class StopInstance
include VagrantPlugins::Azure::Util::MachineIdHelper
include VagrantPlugins::Azure::Util::VMAwait
include VagrantPlugins::Azure::Util::VMStatusTranslator
def initialize(app, env)
@app = app
@ -17,23 +21,34 @@ module VagrantPlugins
end
def call(env)
if env[:machine].state.id == :StoppedDeallocated
env[:ui].info(
I18n.t('vagrant_azure.already_status', :status => 'stopped.')
)
env[:metrics] ||= {}
parsed = parse_machine_id(env[:machine].id)
if env[:machine].state.id == :stopped
env[:ui].info(I18n.t('vagrant_azure.already_status', :status => 'stopped.'))
else
env[:machine].id =~ /@/
VagrantPlugins::WinAzure::CLOUD_SERVICE_SEMAPHORE.synchronize do
env[:ui].info(
I18n.t(
'vagrant_azure.stopping',
:vm_name => $`,
:cloud_service_name => $'
)
)
env[:azure_vm_service].shutdown_virtual_machine($`, $')
env[:ui].info(I18n.t('vagrant_azure.stopping', parsed))
env[:azure_arm_service].compute.virtual_machines.power_off(parsed[:group], parsed[:name])
# Wait for the instance to be ready first
env[:metrics]['instance_stop_time'] = Util::Timer.time do
env[:ui].info(I18n.t('vagrant_azure.waiting_for_stop'))
task = await_true(env) do |vm|
stopped?(vm.properties.instance_view.statuses)
end
if task.value
env[:ui].info(I18n.t('vagrant_azure.stopped', parsed))
else
raise I18n.t('vagrant_azure.errors.failed_starting', parsed) unless env[:interrupted]
end
end
env[:ui].info(I18n.t('vagrant_azure.stopped', parsed))
end
@app.call(env)
end
end

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

@ -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,30 +1,34 @@
#--------------------------------------------------------------------------
# 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'
require 'vagrant-azure/util/machine_id_helper'
module VagrantPlugins
module WinAzure
module Azure
module Action
class TerminateInstance
include VagrantPlugins::Azure::Util::MachineIdHelper
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_azure::action::terminate_instance')
end
def call(env)
env[:machine].id =~ /@/
parsed = parse_machine_id(env[:machine].id)
vm = env[:azure_vm_service].get_virtual_machine($`, $')
if vm.nil?
# machine not found. assuming it was not created or destroyed
env[:ui].info (I18n.t('vagrant_azure.not_created'))
else
env[:azure_vm_service].delete_virtual_machine($`, $')
env[:machine].id = nil
begin
env[:ui].info(I18n.t('vagrant_azure.terminating', parsed))
env[:azure_arm_service].resources.resource_groups.delete(parsed[:group]).value!.body
rescue MsRestAzure::AzureOperationError => ex
unless ex.response.status == 404
raise ex
end
end
env[:ui].info(I18n.t('vagrant_azure.terminated', parsed))
env[:machine].id = nil
@app.call(env)
end

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

@ -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,158 +1,147 @@
#--------------------------------------------------------------------------
# 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
attr_accessor :storage_acct_name
attr_accessor :storage_access_key
# (Optional) Name of the resource group to use.
#
# @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 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
# Password for the VM -- This is not recommended for *nix deployments
#
# @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 :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
@endpoint = UNSET_VALUE
@subscription_id = UNSET_VALUE
@resource_group_name = UNSET_VALUE
@location = 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
@endpoint = (ENV['AZURE_MANAGEMENT_ENDPOINT'] || 'https://management.azure.com') if @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)
errors = _detected_errors
# 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 << I18n.t('vagrant_azure.subscription_id.required') if @subscription_id.nil?
errors << I18n.t('vagrant_azure.mgmt_endpoint.required') if @endpoint.nil?
errors << I18n.t('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

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

@ -0,0 +1,20 @@
module VagrantPlugins
module Azure
module Util
module MachineIdHelper
def parse_machine_id(id)
parts = id.split(':')
{
group: parts[0],
name: parts[1],
location: parts[2]
}
end
def serialize_machine_id(resource_group, vm_name, location)
[resource_group, vm_name, location].join(':')
end
end
end
end
end

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

@ -0,0 +1,15 @@
module VagrantPlugins
module Azure
module Util
class Timer
def self.time
start_time = Time.now.to_f
yield
end_time = Time.now.to_f
end_time - start_time
end
end
end
end
end

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

@ -0,0 +1,36 @@
module VagrantPlugins
module Azure
module Util
module VMAwait
def await_true(env)
config = env[:machine].provider_config
parsed = parse_machine_id(env[:machine].id)
azure = env[:azure_arm_service]
tries = config.instance_ready_timeout / 2
count = 0
task = Concurrent::TimerTask.new(execution_interval: config.instance_check_interval ) do
task.shutdown if env[:interrupted]
if count > tries
task.shutdown
false
end
count += 1
vm = azure.compute.virtual_machines.get(parsed[:group], parsed[:name], 'instanceView').value!.body
if yield(vm)
task.shutdown
true
end
end
task.execute
task.wait_for_termination
task
end
end
end
end
end

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

@ -0,0 +1,59 @@
module VagrantPlugins
module Azure
module Util
module VMStatusTranslator
PROVISIONING_STATES = [:provisioned, :deleting]
POWER_STATES = [:running, :starting, :deallocating, :deallocated]
def vm_status_to_state(status)
code = status.code
case
when code == 'ProvisioningState/succeeded'
:provisioned
when code == 'ProvisioningState/deleting'
:deleting
when code == 'PowerState/running'
:running
when code == 'PowerState/stopping'
:stopping
when code == 'PowerState/stopped'
:stopped
when code == 'PowerState/starting'
:starting
when code == 'PowerState/deallocating'
:deallocating
when code == 'PowerState/deallocated'
:deallocated
else
:unknown
end
end
def power_state(statuses)
vm_status_to_state(statuses.select{ |s| s.code.match(/PowerState/) }.last)
end
def running?(statuses)
statuses.any?{ |s| vm_status_to_state(s) == :running }
end
def built?(statuses)
statuses.any?{ |s| vm_status_to_state(s) == :provisioned }
end
def stopped?(statuses)
statuses.any?{ |s| vm_status_to_state(s) == :stopped }
end
def stopping?(statuses)
statuses.any?{ |s| vm_status_to_state(s) == :stopping }
end
def tearing_down?(statuses)
statuses.any?{ |s| vm_status_to_state(s) == :deleting }
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

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

@ -1,5 +1,7 @@
en:
vagrant_azure:
launching_instance: |-
Launching an instance with the following settings...
not_created: |-
The machine does not exist. Please run `vagrant up` first.
will_not_destroy: |-
@ -7,13 +9,25 @@ en:
already_status: |-
The machine is already %{status}.
stopping: |-
Stopping '%{vm_name}' in '%{cloud_service_name}'
Stopping '%{name}' in '%{group}'
terminating: |-
Terminating '%{name}'
terminated: |-
Terminated '%{name}'
rdp_not_ready: |-
RDP not ready
vm_started: |-
starting: |-
VM '%{name}' is starting
started: |-
VM '%{name}' has been started
vm_stopped: |-
stopping: |-
VM '%{name}' is stopping
stopped: |-
VM '%{name}' has been stopped
restarting: |-
VM '%{name}' is restarting
restarted: |-
VM '%{name}' has been restarted
copy_folder: |-
Copying folder: %{hostpath} ==>
%{guestpath}
@ -35,3 +49,60 @@ en:
Server not created. Error is: %{message}
create_vm_failure: |-
There was some error in creating the VM.
failed_starting: |-
Failed to start VM '%{name}'!!
failed_stopping: |-
Failed to stopping VM '%{name}'!!
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`.
waiting_for_ssh: |-
Waiting for SSH to become available...
ready: |-
Machine is booted and ready for use!
public_key_path_private_key: |-
We expect the public key to be added to the Azure VM to be located at the
same place as the config.ssh.private_key_path + '.pub'. We couldn't find
any public keys for these private key paths:
private_key_not_specified: |-
Please specify a secure key to use with config.ssh.private_key_path
(see: https://www.vagrantup.com/docs/vagrantfile/ssh_settings.html).
If not, you publicly accessible Azure VM will be extremely insecure.
waiting_for_ready: |-
Waiting for instance to become "ready"...
waiting_for_stop: |-
Waiting for instance to become "stopped"...

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,264 @@
{
"$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."
}
},
<% if operating_system == 'Windows' %>
"adminPassword": {
"type": "string",
"metadata": {
"description": "Password for the Virtual Machine (only used on Windows)"
}
},
<% end %>
"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"
}
},
"imageVersion": {
"type": "string",
"defaultValue": "latest",
"metadata": {
"description": "Name of the image sku"
}
},
"subnetName": {
"type": "string",
"defaultValue": "vagrant-subnet",
"metadata": {
"description": "Name of the subnet"
}
},
"virtualNetworkName": {
"type": "string",
"defaultValue": "vagrantVNET",
"metadata": {
"description": "Name of the virtual network"
}
}
},
"variables": {
"storageAccountName": "[concat(uniquestring(resourceGroup().id), 'vagrant')]",
"location": "[resourceGroup().location]",
"osDiskName": "osDisk1",
"addressPrefix": "10.0.0.0/16",
"subnetPrefix": "10.0.0.0/24",
"vmStorageAccountContainerName": "vagrant-vhds",
"nicName": "[concat(parameters('vmName'), '-vagrantNIC')]",
"publicIPAddressName": "[concat(parameters('vmName'), '-vagrantPublicIP')]",
"publicIPAddressType": "Dynamic",
"storageAccountType": "Standard_LRS",
"networkSecurityGroupName": "[concat(parameters('vmName'), '-vagrantNSG')]",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('subnetName'))]",
"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('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]",
"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('subnetRef')]"
}
}
}
]
}
},
{
"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