start, stop, terminate, read_state and auth good

This commit is contained in:
David Justice 2016-03-27 15:09:37 -07:00
Родитель e2b639beb9
Коммит 9411b2da4d
13 изменённых файлов: 268 добавлений и 81 удалений

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

@ -10,7 +10,7 @@ module VagrantPlugins
end
def call(env)
env[:result] = env[:machine].state.id != :stopped
env[:result] = env[:machine].state.id == :stopped
@app.call(env)
end
end

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

@ -2,11 +2,14 @@
# 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 Azure
module Action
class ReadSSHInfo
include VagrantPlugins::Azure::Util::MachineIdHelper
def initialize(app, env, port = 22)
@app = app
@port = port
@ -14,45 +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_arm_service],
env
)
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, env)
return nil if env[:machine].id.nil?
resource_group_name, vm_name = env[:machine].id.split(':')
vm = azure.compute.virtual_machines.get(resource_group_name, vm_name, 'instanceView').value!.body
parsed = parse_machine_id(env[:machine].id)
public_ip = azure.network.public_ipaddresses.get(parsed[:group], "#{parsed[:name]}-vagrantPublicIP").value!.body
if vm.nil?
# Machine cannot be found
@logger.info 'Machine not found. Assuming it was destroyed and cleaning up environment'
terminate(env)
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
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)
{:host => public_ip.properties.dns_settings.fqdn, :port => 22}
end
end
end

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

@ -2,32 +2,36 @@
# 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 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[:azure_arm_service], env)
env[:machine_state_id] = read_state(env[:azure_arm_service], env[:machine])
@app.call(env)
end
def read_state(azure, env)
machine = env[:machine]
def read_state(azure, machine)
return :not_created if machine.id.nil?
# Find the machine
rg_name, vm_name = machine.id.split(':')
parsed = parse_machine_id(machine.id)
vm = nil
begin
vm = azure.compute.virtual_machines.get(rg_name, vm_name, 'instanceView').value!.body
vm = azure.compute.virtual_machines.get(parsed[:group], parsed[:name], 'instanceView').value!.body
rescue MsRestAzure::AzureOperationError => ex
if vm.nil? || [:'shutting-down', :terminated].include?(vm.state.to_sym)
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
@ -36,7 +40,7 @@ module VagrantPlugins
end
# Return the state
vm.state.to_sym
power_state(vm.properties.instance_view.statuses)
end
end

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

@ -2,22 +2,24 @@
# 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 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

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

@ -6,6 +6,7 @@ require 'json'
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
@ -13,6 +14,7 @@ module VagrantPlugins
module Action
class RunInstance
include Vagrant::Util::Retryable
include VagrantPlugins::Azure::Util::MachineIdHelper
def initialize(app, env)
@app = app
@ -23,8 +25,10 @@ module VagrantPlugins
# Initialize metrics if they haven't been
env[:metrics] ||= {}
machine = env[:machine]
# Get the configs
config = env[:machine].provider_config
config = machine.provider_config
endpoint = config.endpoint
resource_group_name = config.resource_group_name
location = config.location
@ -61,7 +65,6 @@ module VagrantPlugins
@logger.info("Time to fetch os image details: #{env[:metrics]['get_image_details']}")
deployment_params = {
sshKeyData: File.read(File.expand_path('~/.ssh/id_rsa.pub')),
dnsLabelPrefix: Haikunator.haikunate(100),
vmSize: vm_size,
vmName: vm_name,
@ -73,11 +76,22 @@ module VagrantPlugins
virtualNetworkName: virtual_network_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)
operating_system: get_image_os(image_details)
}
env[:ui].info(" -- Putting Resource Group: #{resource_group_name}")
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
@ -92,7 +106,7 @@ module VagrantPlugins
env[:ui].info('Finished deploying')
# Immediately save the ID since it is created at this point.
env[:machine].id = "#{resource_group_name}:#{vm_name}"
env[:machine].id = serialize_machine_id(resource_group_name, vm_name, location)
@logger.info("Time to deploy: #{env[:metrics]['deployment_time']}")
unless env[:interrupted]

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

@ -2,29 +2,50 @@
# 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'
# Bare bones basic implementation. This a work in progress in very early stages
module VagrantPlugins
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::Azure::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

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

@ -2,12 +2,18 @@
# 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'
# Bare bones basic implementation. This a work in progress in very early stages
module VagrantPlugins
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
@ -15,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::Azure::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

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

@ -2,20 +2,32 @@
# 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 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)
rg_name, vm_name = env[:machine].id.split(':')
parsed = parse_machine_id(env[:machine].id)
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[:azure_arm_service].compute.virtual_machines.delete(rg_name, vm_name).value!.body
env[:machine].id = nil
@app.call(env)

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

@ -28,7 +28,7 @@ module VagrantPlugins
# @return [String]
attr_accessor :subscription_id
# (Optional) Name of the resource group to use. WARNING: the resource group will be removed upon destroy!!!
# (Optional) Name of the resource group to use.
#
# @return [String]
attr_accessor :resource_group_name

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

@ -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,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

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

@ -9,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}
@ -37,6 +49,10 @@ 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.
@ -78,3 +94,15 @@ en:
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"...