chef-provisioning-azure 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e42ada83026bc0b71619981f7011348cd7cfdbf
4
- data.tar.gz: 27ba52487d1b312a1e7f7f1df15d0a2e284ce751
3
+ metadata.gz: 4dc56508086b8397f5e1e4eab691392011eca2bb
4
+ data.tar.gz: a77798d891a143c7d2a2d7d30cbd662d09d2e33e
5
5
  SHA512:
6
- metadata.gz: 637d41bc82b384c8ab6fcf2c29485fdc36b29a36b28e41da47d2fea011bdba5c9e5ee19fdb220aa918f6daa128195f565087dc50e02d80ba8ba074e1474ba442
7
- data.tar.gz: 4c4ea2abad65486614993bf7f54acdab970907a26d1dfb4d7f8107c56bce3d64b025de5693fac1e18948bc5e470823aa0a93951cdfbd3b739dc4b6739421d1c5
6
+ metadata.gz: 7997caedf65e4e61cc99dad763aa33d455aef004fb3f4faacce780b00d9497dd54f462be804132900757f830f6d3d7566c57bf7a1b9ddd48af929b71d8d945d2
7
+ data.tar.gz: 2b5388bea4b4b3cda7c95b5a7bbf85088c1a522992163f0067d0f0eafdc106829f7e61df20d1d0a04076555f7425215478f110652a5fd415f8ae74878aab4b9f
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
  gemspec
3
3
 
4
+ gem "chef", git: "https://github.com/chef/chef" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.2.2") # until stable 12.14 is released (won't load new cheffish and such otherwise)
5
+
4
6
  # If you want to customize your local install, you can add stuff to Gemfile.local, which doesn't go to git
5
7
  eval(IO.read("#{__FILE__}.local")) if File.exist?("#{__FILE__}.local")
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
- [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/chef/chef-provisioning?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
2
-
3
1
  # chef-provisioning-azure
4
2
 
3
+ [![Build Status](https://travis-ci.org/chef/chef-provisioning-azure.svg?branch=master)](https://travis-ci.org/chef/chef-provisioning-azure) [![Gem Version](https://badge.fury.io/rb/chef-provisioning-azure.svg)](https://badge.fury.io/rb/chef-provisioning-azure)
4
+
5
5
  This is an implementation of an Microsoft Azure driver for [chef-provisioning](/chef/chef-provisioning) that relies on [azure-sdk-for-ruby](https://github.com/stuartpreston/stuartpreston-azure-sdk-for-ruby) and the Azure Service Management API.
6
6
 
7
7
  **Please note this driver does not support Azure Resource Manager (ARM) and is therefore only able to create "classic" VM resources that sit behind a cloud service in Azure. A new driver is under development - see [chef-provisioning-azurerm](https://github.com/pendrica/chef-provisioning-azurerm).**
@@ -67,28 +67,30 @@ machine 'toad' do
67
67
  end
68
68
  ```
69
69
 
70
- Note that images are not kept historically in Azure, therefore to find the latest images for your platform use the command ```azure vm image list``` to ensure the public image you require is available.
70
+ Note that images are not kept historically in Azure, therefore to find the latest images for your platform use the command `azure vm image list` to ensure the public image you require is available.
71
71
 
72
72
  ## Supported Features
73
- * Automatic creation and teardown of Cloud Services
74
- * Public (OS) images and captured User (VM) images
75
- * Up to date (March 2015) VM sizes including 'D', 'DS', 'G', A10/A11 sizes.
76
- * Custom TCP/UDP endpoints per VM role
77
- * Linux VMs, SSH external bootstrap via cloud service endpoint
78
- * Windows VMs, WinRM bootstrap via cloud service endpoint
73
+
74
+ - Automatic creation and teardown of Cloud Services
75
+ - Public (OS) images and captured User (VM) images
76
+ - Up to date (March 2015) VM sizes including 'D', 'DS', 'G', A10/A11 sizes.
77
+ - Custom TCP/UDP endpoints per VM role
78
+ - Linux VMs, SSH external bootstrap via cloud service endpoint
79
+ - Windows VMs, WinRM bootstrap via cloud service endpoint
79
80
 
80
81
  ## Unsupported/will not work
81
- * Load-balanced sets
82
- * Availability sets/Fault domains
83
- * Cloud Service autoscaling
84
- * Endpoint monitoring
85
- * Additional disk volumes
86
- * Affinity groups
87
- * Direct server return IP addresses
88
- * Reserved/Static IP addresses
89
- * Virtual network allocation
90
- * Bootstrap via internal (private) addresses
91
- * Non-IaaS Azure services (e.g CDN/TrafficManager, Service Bus, Azure SQL Database, Media Services, Redis Cache)
82
+
83
+ - Load-balanced sets
84
+ - Availability sets/Fault domains
85
+ - Cloud Service autoscaling
86
+ - Endpoint monitoring
87
+ - Additional disk volumes
88
+ - Affinity groups
89
+ - Direct server return IP addresses
90
+ - Reserved/Static IP addresses
91
+ - Virtual network allocation
92
+ - Bootstrap via internal (private) addresses
93
+ - Non-IaaS Azure services (e.g CDN/TrafficManager, Service Bus, Azure SQL Database, Media Services, Redis Cache)
92
94
 
93
95
  **This driver is no longer under active development as the creation of resources under Service Management mode in Azure is being deprecated in favour of Azure Resource Manager.**
94
96
 
@@ -102,7 +104,6 @@ chef gem install chef-provisioning-azure
102
104
 
103
105
  ### Setting your credentials (v0.3 and above)
104
106
 
105
- * If you have previously connected to your Azure subscription using the [azure-cli](http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-command-line-tools/) tools and imported your publishSettings (by using ```azure account download``` and ```azure account import <filename.publishSettings>```), **you do not need to do anything else** the driver will read your profile information and certificates from ~/.azure/azureProfile.json
106
- * Alternatively, we support any of the methods listed in [configuration](docs/configuration.md) to set the driver up with access to your subscription
107
- * Note that the use of ~/.azure/config to configure the driver is **no longer supported**.
108
-
107
+ - If you have previously connected to your Azure subscription using the [azure-cli](http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-command-line-tools/) tools and imported your publishSettings (by using `azure account download` and `azure account import <filename.publishSettings>`), **you do not need to do anything else** the driver will read your profile information and certificates from ~/.azure/azureProfile.json
108
+ - Alternatively, we support any of the methods listed in [configuration](docs/configuration.md) to set the driver up with access to your subscription
109
+ - Note that the use of ~/.azure/config to configure the driver is **no longer supported**.
@@ -1,33 +1,34 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__) + '/lib')
2
- require 'chef/provisioning/azure_driver/version'
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/lib")
2
+ require "chef/provisioning/azure_driver/version"
3
3
 
4
4
  Gem::Specification.new do |s|
5
- s.name = 'chef-provisioning-azure'
5
+ s.name = "chef-provisioning-azure"
6
6
  s.version = Chef::Provisioning::AzureDriver::VERSION
7
7
  s.platform = Gem::Platform::RUBY
8
- s.extra_rdoc_files = %w(README.md LICENSE)
9
- s.summary = 'Provisioner for creating Microsoft Azure resources using ' \
10
- 'Chef Provisioning.'
11
- s.description = 'This is a driver that works with chef-provisioning that ' \
12
- 'allows Chef Provisioning to manage objects in Microsoft Azure.'
13
- s.author = 'John Ewart'
14
- s.email = 'jewart@getchef.com'
15
- s.homepage = 'https://github.com/chef/chef-provisioning-azure'
16
- s.license = 'Apache-2.0'
8
+ s.extra_rdoc_files = %w{README.md LICENSE}
9
+ s.summary = "Provisioner for creating Microsoft Azure resources using " \
10
+ "Chef Provisioning."
11
+ s.description = "This is a driver that works with chef-provisioning that " \
12
+ "allows Chef Provisioning to manage objects in Microsoft Azure."
13
+ s.author = "John Ewart"
14
+ s.email = "jewart@chef.io"
15
+ s.homepage = "https://github.com/chef/chef-provisioning-azure"
16
+ s.license = "Apache-2.0"
17
17
 
18
- s.add_dependency 'chef-provisioning', '~> 1.0'
19
- s.add_dependency 'stuartpreston-azure-sdk-for-ruby', '~> 0.7'
18
+ s.add_dependency "chef-provisioning", ">= 1.0", "< 3.0"
19
+ s.add_dependency "stuartpreston-azure-sdk-for-ruby", "~> 0.7"
20
20
 
21
- s.add_development_dependency 'chef', '>= 12.0'
22
- s.add_development_dependency 'rspec'
23
- s.add_development_dependency 'rake'
24
- s.add_development_dependency 'yard'
25
- s.add_development_dependency 'github_changelog_generator'
21
+ s.add_development_dependency "chef", ">= 12.0"
22
+ s.add_development_dependency "rspec"
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "yard"
25
+ s.add_development_dependency "github_changelog_generator"
26
+ s.add_development_dependency "chefstyle", "~> 0.4.0"
26
27
 
27
- s.bindir = 'bin'
28
- s.executables = %w( )
28
+ s.bindir = "bin"
29
+ s.executables = %w{ }
29
30
 
30
- s.require_path = 'lib'
31
- s.files = %w(Gemfile Rakefile LICENSE README.md) + Dir.glob('*.gemspec')
32
- s.files += Dir.glob('{distro,lib,tasks,spec}/**/*', File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
31
+ s.require_path = "lib"
32
+ s.files = %w{Gemfile Rakefile LICENSE README.md} + Dir.glob("*.gemspec")
33
+ s.files += Dir.glob("{distro,lib,tasks,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
33
34
  end
@@ -1,4 +1,4 @@
1
- require 'chef/provisioning/azure_driver/azure_provider'
1
+ require "chef/provisioning/azure_driver/azure_provider"
2
2
 
3
3
  class Chef
4
4
  class Provider
@@ -1,4 +1,4 @@
1
- require 'chef/provisioning/azure_driver/azure_provider'
1
+ require "chef/provisioning/azure_driver/azure_provider"
2
2
 
3
3
  class Chef
4
4
  class Provider
@@ -14,11 +14,11 @@ class Chef
14
14
  "#{new_resource.options[:location]}")
15
15
  server = properties.name
16
16
 
17
- new_resource.options[:firewall_rules].each do | rule |
18
- rule_name = URI::encode(rule[:name])
17
+ new_resource.options[:firewall_rules].each do |rule|
18
+ rule_name = URI.encode(rule[:name])
19
19
  range = {
20
20
  :start_ip_address => rule[:start_ip_address],
21
- :end_ip_address => rule[:end_ip_address]
21
+ :end_ip_address => rule[:end_ip_address],
22
22
  }
23
23
  csql.set_sql_server_firewall_rule(server, rule_name, range)
24
24
  end
@@ -29,7 +29,7 @@ class Chef
29
29
 
30
30
  action :destroy do
31
31
  # not supported
32
- fail "Destroy not yet implemented on Azure SQL Server using ASM."
32
+ raise "Destroy not yet implemented on Azure SQL Server using ASM."
33
33
  end
34
34
  end
35
35
  end
@@ -1,4 +1,4 @@
1
- require 'chef/provisioning/azure_driver/azure_provider'
1
+ require "chef/provisioning/azure_driver/azure_provider"
2
2
 
3
3
  class Chef
4
4
  class Provider
@@ -1,3 +1,3 @@
1
- require 'chef/provisioning'
2
- require 'chef/provisioning/azure_driver/driver'
3
- require 'chef/provisioning/azure_driver/resources'
1
+ require "chef/provisioning"
2
+ require "chef/provisioning/azure_driver/driver"
3
+ require "chef/provisioning/azure_driver/resources"
@@ -1,7 +1,7 @@
1
- require 'chef/provider/lwrp_base'
2
- require 'chef/provisioning/azure_driver/azure_resource'
3
- require 'chef/provisioning/chef_provider_action_handler'
4
- require 'azure'
1
+ require "chef/provider/lwrp_base"
2
+ require "chef/provisioning/azure_driver/azure_resource"
3
+ require "chef/provisioning/chef_provider_action_handler"
4
+ require "azure"
5
5
 
6
6
  class Chef
7
7
  module Provisioning
@@ -12,7 +12,7 @@ class Chef
12
12
  AzureResource = Chef::Provisioning::AzureDriver::AzureResource
13
13
 
14
14
  def azure_sql_management_endpoint
15
- 'https://management.database.windows.net:8443'
15
+ "https://management.database.windows.net:8443"
16
16
  end
17
17
 
18
18
  def action_handler
@@ -1,5 +1,5 @@
1
- require 'chef/resource/lwrp_base'
2
- require 'chef/provisioning/azure_driver/subscriptions'
1
+ require "chef/resource/lwrp_base"
2
+ require "chef/provisioning/azure_driver/subscriptions"
3
3
 
4
4
  class Chef
5
5
  module Provisioning
@@ -14,7 +14,7 @@ class Chef
14
14
  end
15
15
 
16
16
  config = run_context.chef_provisioning.config
17
- scheme, account_id = driver.split(':', 2)
17
+ scheme, account_id = driver.split(":", 2)
18
18
 
19
19
  if account_id.nil? || account_id.empty?
20
20
  subscription = Subscriptions.default_subscription(config)
@@ -43,7 +43,7 @@ class Chef
43
43
  attribute :driver
44
44
  attribute :chef_server, kind_of: Hash
45
45
  attribute :managed_entry_store, kind_of: Chef::Provisioning::ManagedEntryStore,
46
- lazy_default: proc { Chef::Provisioning::ChefManagedEntryStore.new(chef_server) }
46
+ lazy_default: proc { Chef::Provisioning::ChefManagedEntryStore.new(chef_server) }
47
47
  attribute :subscription
48
48
  end
49
49
  end
@@ -1,25 +1,25 @@
1
1
  class Chef
2
- module Provisioning
3
- module AzureDriver
4
- # Represents available options when bootstrapping a host on Azure
5
- # These are used to tell Azure some initial pieces of information
6
- # for building a new VM.
7
- class BootstrapOptions < Chef::Provisioning::BootstrapOptions
8
- # @return [String] The name of the VM
9
- attr_accessor :vm_name
2
+ module Provisioning
3
+ module AzureDriver
4
+ # Represents available options when bootstrapping a host on Azure
5
+ # These are used to tell Azure some initial pieces of information
6
+ # for building a new VM.
7
+ class BootstrapOptions < Chef::Provisioning::BootstrapOptions
8
+ # @return [String] The name of the VM
9
+ attr_accessor :vm_name
10
10
 
11
- # @return [String] The VM user
12
- attr_accessor :vm_user
11
+ # @return [String] The VM user
12
+ attr_accessor :vm_user
13
13
 
14
- # @return [String] The identifier for the VM image to use
15
- attr_accessor :image
14
+ # @return [String] The identifier for the VM image to use
15
+ attr_accessor :image
16
16
 
17
- # @return [String] the password to use
18
- attr_accessor :password
17
+ # @return [String] the password to use
18
+ attr_accessor :password
19
19
 
20
- # @return [String] The Azure location to store this in
21
- attr_accessor :location
20
+ # @return [String] The Azure location to store this in
21
+ attr_accessor :location
22
+ end
23
+ end
22
24
  end
23
25
  end
24
- end
25
- end
@@ -1,34 +1,34 @@
1
1
  class Chef
2
- module Provisioning
3
- module AzureDriver
4
- # A collection of useful Azure-specific constants
5
- class Constants
6
- # Constants around transport mechanisms available
7
- class Transport
8
- HTTP = 'http'
9
- HTTPS = 'https'
10
- end
2
+ module Provisioning
3
+ module AzureDriver
4
+ # A collection of useful Azure-specific constants
5
+ class Constants
6
+ # Constants around transport mechanisms available
7
+ class Transport
8
+ HTTP = "http"
9
+ HTTPS = "https"
10
+ end
11
11
 
12
- # Constants for describing VM sizes in Azure
13
- class MachineSize
14
- # Put in machine specs here...
15
- EXTRASMALL = 'ExtraSmall'
16
- # What is this?
17
- SMALL = 'Small'
18
- # Are these now A2?
19
- MEDIUM = 'Medium'
20
- LARGE = 'Large'
21
- XLARGE = 'ExtraLarge'
22
- A5 = 'A5'
23
- A6 = 'A6'
24
- A7 = 'A7'
25
- BASIC_A0 = 'Basic_A0'
26
- BASIC_A1 = 'Basic_A1'
27
- BASIC_A2 = 'Basic_A2'
28
- BASIC_A3 = 'Basic_A3'
29
- BASIC_A4 = 'Basic_A4'
12
+ # Constants for describing VM sizes in Azure
13
+ class MachineSize
14
+ # Put in machine specs here...
15
+ EXTRASMALL = "ExtraSmall"
16
+ # What is this?
17
+ SMALL = "Small"
18
+ # Are these now A2?
19
+ MEDIUM = "Medium"
20
+ LARGE = "Large"
21
+ XLARGE = "ExtraLarge"
22
+ A5 = "A5"
23
+ A6 = "A6"
24
+ A7 = "A7"
25
+ BASIC_A0 = "Basic_A0"
26
+ BASIC_A1 = "Basic_A1"
27
+ BASIC_A2 = "Basic_A2"
28
+ BASIC_A3 = "Basic_A3"
29
+ BASIC_A4 = "Basic_A4"
30
+ end
31
+ end
30
32
  end
31
33
  end
32
34
  end
33
- end
34
- end
@@ -1,360 +1,360 @@
1
- require 'chef/mixin/shell_out'
2
- require 'chef/provisioning/driver'
3
- require 'chef/provisioning/convergence_strategy/install_cached'
4
- require 'chef/provisioning/convergence_strategy/install_sh'
5
- require 'chef/provisioning/convergence_strategy/install_msi'
6
- require 'chef/provisioning/convergence_strategy/no_converge'
7
- require 'chef/provisioning/transport/ssh'
8
- require 'chef/provisioning/transport/winrm'
9
- require 'chef/provisioning/machine/windows_machine'
10
- require 'chef/provisioning/machine/unix_machine'
11
- require 'chef/provisioning/machine_spec'
12
-
13
- require 'chef/provisioning/azure_driver/version'
14
- require 'chef/provisioning/azure_driver/subscriptions'
15
-
16
- require 'yaml'
17
- require 'azure'
1
+ require "chef/mixin/shell_out"
2
+ require "chef/provisioning/driver"
3
+ require "chef/provisioning/convergence_strategy/install_cached"
4
+ require "chef/provisioning/convergence_strategy/install_sh"
5
+ require "chef/provisioning/convergence_strategy/install_msi"
6
+ require "chef/provisioning/convergence_strategy/no_converge"
7
+ require "chef/provisioning/transport/ssh"
8
+ require "chef/provisioning/transport/winrm"
9
+ require "chef/provisioning/machine/windows_machine"
10
+ require "chef/provisioning/machine/unix_machine"
11
+ require "chef/provisioning/machine_spec"
12
+
13
+ require "chef/provisioning/azure_driver/version"
14
+ require "chef/provisioning/azure_driver/subscriptions"
15
+
16
+ require "yaml"
17
+ require "azure"
18
18
 
19
19
  class Chef
20
- module Provisioning
21
- module AzureDriver
22
- # Provisions machines using the Azure SDK
23
- class Driver < Chef::Provisioning::Driver
24
- attr_reader :region
25
-
26
- # Construct an AzureDriver object from a URL - used to parse existing URL
27
- # data to hydrate a driver object.
28
- # URL scheme:
29
- # azure:subscription_id
30
- # @return [AzureDriver] A chef-provisioning Azure driver object for the given URL
31
- def self.from_url(driver_url, config)
32
- Driver.new(driver_url, config)
33
- end
34
-
35
- def self.canonicalize_url(driver_url, config)
36
- scheme, account_id = driver_url.split(':', 2)
37
- if account_id.nil? || account_id.empty?
38
- subscription = Subscriptions.default_subscription(config)
39
- if !subscription
40
- raise "Driver #{driver_url} did not specify a subscription ID, and no default subscription was found. Have you downloaded the Azure CLI and used `azure account download` and `azure account import` to set up Azure? Alternately, you can set azure_subscriptions to [ { subscription_id: '...', management_credentials: ... }] in your Chef configuration."
20
+ module Provisioning
21
+ module AzureDriver
22
+ # Provisions machines using the Azure SDK
23
+ class Driver < Chef::Provisioning::Driver
24
+ attr_reader :region
25
+
26
+ # Construct an AzureDriver object from a URL - used to parse existing URL
27
+ # data to hydrate a driver object.
28
+ # URL scheme:
29
+ # azure:subscription_id
30
+ # @return [AzureDriver] A chef-provisioning Azure driver object for the given URL
31
+ def self.from_url(driver_url, config)
32
+ Driver.new(driver_url, config)
41
33
  end
42
- config = Cheffish::MergedConfig.new({ azure_subscriptions: subscription }, config)
43
- end
44
- if subscription
45
- [ "#{scheme}:#{subscription[:subscription_id]}", config ]
46
- else
47
- [ driver_url, config]
48
- end
49
- end
50
-
51
- def initialize(driver_url, config)
52
- super
53
- scheme, subscription_id = driver_url.split(':', 2)
54
- @subscription = Subscriptions.get_subscription(config, subscription_id)
55
- if !subscription
56
- raise "Driver #{driver_url} has a subscription ID, but the system has no credentials configured for it! If you have access to this subscription, you can use `azure account download` and `azure account import` in the Azure CLI to get the credentials, or set azure_subscriptions to [ { subscription_id: '...', management_credentials: ... }] in your Chef configuration."
57
- end
58
-
59
- # TODO make this instantiable so we can have multiple drivers ......
60
- Azure.configure do |azure|
61
- # Configure these 3 properties to use Storage
62
- azure.management_certificate = subscription[:management_certificate]
63
- azure.subscription_id = subscription[:subscription_id]
64
- azure.management_endpoint = subscription[:management_endpoint]
65
- end
66
- end
67
-
68
- attr_reader :subscription
69
-
70
- # -- Machine methods --
71
-
72
- # Allocate a new machine with the Azure API and start it up, without
73
- # blocking to wait for it. Creates any needed resources to get a machine
74
- # up and running.
75
- # @param (see Chef::Provisioning::Driver#allocate_machine)
76
- def allocate_machine(action_handler, machine_spec, machine_options)
77
- existing_vm = vm_for(machine_spec)
78
-
79
- # We don't need to do anything if the existing VM is found
80
- return if existing_vm
81
-
82
- bootstrap_options = machine_options[:bootstrap_options] || {}
83
- bootstrap_options[:vm_size] ||= 'Small'
84
- bootstrap_options[:cloud_service_name] ||= 'chefprovisioning'
85
- bootstrap_options[:storage_account_name] ||= 'chefprovisioning'
86
- bootstrap_options[:location] ||= 'West US'
87
-
88
- location = bootstrap_options[:location]
89
-
90
- machine_spec.location = {
91
- 'driver_url' => driver_url,
92
- 'driver_version' => Chef::Provisioning::AzureDriver::VERSION,
93
- 'allocated_at' => Time.now.utc.to_s,
94
- 'host_node' => action_handler.host_node,
95
- 'image_id' => machine_options[:image_id],
96
- 'location' => location,
97
- 'cloud_service' => bootstrap_options[:cloud_service_name]
98
- }
99
-
100
- image_id = machine_options[:image_id] || default_image_for_location(location)
101
-
102
- Chef::Log.debug "Azure bootstrap options: #{bootstrap_options.inspect}"
103
-
104
- params = {
105
- vm_name: machine_spec.name,
106
- vm_user: bootstrap_options[:vm_user] || default_ssh_username,
107
- image: image_id,
108
- # This is only until SSH keys are added
109
- password: machine_options[:password],
110
- location: location,
111
- cloud_service_name: bootstrap_options[:cloud_service_name]
112
- }
113
-
114
- # If the cloud service exists already, need to add a role to it - otherwise create virtual machine (including cloud service)
115
- cloud_service = azure_cloud_service_service.get_cloud_service(bootstrap_options[:cloud_service_name])
116
- existing_deployment = azure_vm_service.list_virtual_machines(bootstrap_options[:cloud_service_name]).any?
117
-
118
- if cloud_service and existing_deployment
119
- action_handler.report_progress "Cloud Service #{bootstrap_options[:cloud_service_name]} already exists, adding role."
120
- action_handler.report_progress "Creating #{machine_spec.name} with image #{image_id} in #{bootstrap_options[:cloud_service_name]}..."
121
- vm = azure_vm_service.add_role(params, bootstrap_options)
122
- else
123
- action_handler.report_progress "Creating #{machine_spec.name} with image #{image_id} in #{location}..."
124
- vm = azure_vm_service.create_virtual_machine(params, bootstrap_options)
125
- end
126
-
127
- machine_spec.location['vm_name'] = vm.vm_name
128
- machine_spec.location['is_windows'] = (true if vm.os_type == 'Windows') || false
129
- action_handler.report_progress "Created #{vm.vm_name} in #{location}..."
130
- end
131
-
132
- # (see Chef::Provisioning::Driver#ready_machine)
133
- def ready_machine(action_handler, machine_spec, machine_options)
134
- vm = vm_for(machine_spec)
135
- location = machine_spec.location['location']
136
-
137
- if vm.nil?
138
- fail "Machine #{machine_spec.name} does not have a VM associated with it, or the VM does not exist."
139
- end
140
34
 
141
- # TODO: Not sure if this is the right thing to check
142
- if vm.status != 'ReadyRole'
143
- action_handler.report_progress "Readying #{machine_spec.name} in #{location}..."
144
- wait_until_ready(action_handler, machine_spec)
145
- wait_for_transport(action_handler, machine_spec, machine_options)
146
- else
147
- action_handler.report_progress "#{machine_spec.name} already ready in #{location}!"
148
- end
149
-
150
- machine_for(machine_spec, machine_options, vm)
151
- end
35
+ def self.canonicalize_url(driver_url, config)
36
+ scheme, account_id = driver_url.split(":", 2)
37
+ if account_id.nil? || account_id.empty?
38
+ subscription = Subscriptions.default_subscription(config)
39
+ if !subscription
40
+ raise "Driver #{driver_url} did not specify a subscription ID, and no default subscription was found. Have you downloaded the Azure CLI and used `azure account download` and `azure account import` to set up Azure? Alternately, you can set azure_subscriptions to [ { subscription_id: '...', management_credentials: ... }] in your Chef configuration."
41
+ end
42
+ config = Cheffish::MergedConfig.new({ azure_subscriptions: subscription }, config)
43
+ end
44
+ if subscription
45
+ [ "#{scheme}:#{subscription[:subscription_id]}", config ]
46
+ else
47
+ [ driver_url, config]
48
+ end
49
+ end
152
50
 
153
- # (see Chef::Provisioning::Driver#destroy_machine)
154
- def destroy_machine(action_handler, machine_spec, machine_options)
155
- vm = vm_for(machine_spec)
156
- vm_name = machine_spec.name
157
- cloud_service = machine_spec.location['cloud_service']
51
+ def initialize(driver_url, config)
52
+ super
53
+ scheme, subscription_id = driver_url.split(":", 2)
54
+ @subscription = Subscriptions.get_subscription(config, subscription_id)
55
+ if !subscription
56
+ raise "Driver #{driver_url} has a subscription ID, but the system has no credentials configured for it! If you have access to this subscription, you can use `azure account download` and `azure account import` in the Azure CLI to get the credentials, or set azure_subscriptions to [ { subscription_id: '...', management_credentials: ... }] in your Chef configuration."
57
+ end
58
+
59
+ # TODO make this instantiable so we can have multiple drivers ......
60
+ Azure.configure do |azure|
61
+ # Configure these 3 properties to use Storage
62
+ azure.management_certificate = subscription[:management_certificate]
63
+ azure.subscription_id = subscription[:subscription_id]
64
+ azure.management_endpoint = subscription[:management_endpoint]
65
+ end
66
+ end
158
67
 
159
- # Check if we need to proceed
160
- return if vm.nil? || vm_name.nil? || cloud_service.nil?
68
+ attr_reader :subscription
69
+
70
+ # -- Machine methods --
71
+
72
+ # Allocate a new machine with the Azure API and start it up, without
73
+ # blocking to wait for it. Creates any needed resources to get a machine
74
+ # up and running.
75
+ # @param (see Chef::Provisioning::Driver#allocate_machine)
76
+ def allocate_machine(action_handler, machine_spec, machine_options)
77
+ existing_vm = vm_for(machine_spec)
78
+
79
+ # We don't need to do anything if the existing VM is found
80
+ return if existing_vm
81
+
82
+ bootstrap_options = machine_options[:bootstrap_options] || {}
83
+ bootstrap_options[:vm_size] ||= "Small"
84
+ bootstrap_options[:cloud_service_name] ||= "chefprovisioning"
85
+ bootstrap_options[:storage_account_name] ||= "chefprovisioning"
86
+ bootstrap_options[:location] ||= "West US"
87
+
88
+ location = bootstrap_options[:location]
89
+
90
+ machine_spec.location = {
91
+ "driver_url" => driver_url,
92
+ "driver_version" => Chef::Provisioning::AzureDriver::VERSION,
93
+ "allocated_at" => Time.now.utc.to_s,
94
+ "host_node" => action_handler.host_node,
95
+ "image_id" => machine_options[:image_id],
96
+ "location" => location,
97
+ "cloud_service" => bootstrap_options[:cloud_service_name],
98
+ }
99
+
100
+ image_id = machine_options[:image_id] || default_image_for_location(location)
101
+
102
+ Chef::Log.debug "Azure bootstrap options: #{bootstrap_options.inspect}"
103
+
104
+ params = {
105
+ vm_name: machine_spec.name,
106
+ vm_user: bootstrap_options[:vm_user] || default_ssh_username,
107
+ image: image_id,
108
+ # This is only until SSH keys are added
109
+ password: machine_options[:password],
110
+ location: location,
111
+ cloud_service_name: bootstrap_options[:cloud_service_name],
112
+ }
113
+
114
+ # If the cloud service exists already, need to add a role to it - otherwise create virtual machine (including cloud service)
115
+ cloud_service = azure_cloud_service_service.get_cloud_service(bootstrap_options[:cloud_service_name])
116
+ existing_deployment = azure_vm_service.list_virtual_machines(bootstrap_options[:cloud_service_name]).any?
117
+
118
+ if cloud_service && existing_deployment
119
+ action_handler.report_progress "Cloud Service #{bootstrap_options[:cloud_service_name]} already exists, adding role."
120
+ action_handler.report_progress "Creating #{machine_spec.name} with image #{image_id} in #{bootstrap_options[:cloud_service_name]}..."
121
+ vm = azure_vm_service.add_role(params, bootstrap_options)
122
+ else
123
+ action_handler.report_progress "Creating #{machine_spec.name} with image #{image_id} in #{location}..."
124
+ vm = azure_vm_service.create_virtual_machine(params, bootstrap_options)
125
+ end
126
+
127
+ machine_spec.location["vm_name"] = vm.vm_name
128
+ machine_spec.location["is_windows"] = (true if vm.os_type == "Windows") || false
129
+ action_handler.report_progress "Created #{vm.vm_name} in #{location}..."
130
+ end
161
131
 
162
- # Skip if we don't actually need to do anything
163
- return unless action_handler.should_perform_actions
132
+ # (see Chef::Provisioning::Driver#ready_machine)
133
+ def ready_machine(action_handler, machine_spec, machine_options)
134
+ vm = vm_for(machine_spec)
135
+ location = machine_spec.location["location"]
136
+
137
+ if vm.nil?
138
+ raise "Machine #{machine_spec.name} does not have a VM associated with it, or the VM does not exist."
139
+ end
140
+
141
+ # TODO: Not sure if this is the right thing to check
142
+ if vm.status != "ReadyRole"
143
+ action_handler.report_progress "Readying #{machine_spec.name} in #{location}..."
144
+ wait_until_ready(action_handler, machine_spec)
145
+ wait_for_transport(action_handler, machine_spec, machine_options)
146
+ else
147
+ action_handler.report_progress "#{machine_spec.name} already ready in #{location}!"
148
+ end
149
+
150
+ machine_for(machine_spec, machine_options, vm)
151
+ end
164
152
 
165
- # TODO: action_handler.do |block| ?
166
- action_handler.report_progress "Destroying VM #{machine_spec.name}!"
167
- azure_vm_service.delete_virtual_machine(vm_name, cloud_service)
168
- action_handler.report_progress "Destroyed VM #{machine_spec.name}!"
169
- end
153
+ # (see Chef::Provisioning::Driver#destroy_machine)
154
+ def destroy_machine(action_handler, machine_spec, machine_options)
155
+ vm = vm_for(machine_spec)
156
+ vm_name = machine_spec.name
157
+ cloud_service = machine_spec.location["cloud_service"]
170
158
 
171
- private
159
+ # Check if we need to proceed
160
+ return if vm.nil? || vm_name.nil? || cloud_service.nil?
172
161
 
173
- def machine_for(machine_spec, machine_options, vm = nil)
174
- vm ||= vm_for(machine_spec)
162
+ # Skip if we don't actually need to do anything
163
+ return unless action_handler.should_perform_actions
175
164
 
176
- fail "VM for node #{machine_spec.name} has not been created!" unless vm
165
+ # TODO: action_handler.do |block| ?
166
+ action_handler.report_progress "Destroying VM #{machine_spec.name}!"
167
+ azure_vm_service.delete_virtual_machine(vm_name, cloud_service)
168
+ action_handler.report_progress "Destroyed VM #{machine_spec.name}!"
169
+ end
177
170
 
178
- transport = transport_for(machine_spec, machine_options, vm)
179
- convergence_strategy = convergence_strategy_for(machine_spec, machine_options)
171
+ private
180
172
 
181
- if machine_spec.location['is_windows']
182
- Chef::Provisioning::Machine::WindowsMachine.new(machine_spec, transport, convergence_strategy)
183
- else
184
- Chef::Provisioning::Machine::UnixMachine.new(machine_spec, transport, convergence_strategy)
185
- end
186
- end
173
+ def machine_for(machine_spec, machine_options, vm = nil)
174
+ vm ||= vm_for(machine_spec)
187
175
 
188
- def azure_vm_service
189
- @vm_service ||= Azure::VirtualMachineManagementService.new
190
- end
176
+ raise "VM for node #{machine_spec.name} has not been created!" unless vm
191
177
 
192
- def azure_cloud_service_service
193
- @cloud_service_service ||= Azure::CloudServiceManagementService.new
194
- end
178
+ transport = transport_for(machine_spec, machine_options, vm)
179
+ convergence_strategy = convergence_strategy_for(machine_spec, machine_options)
195
180
 
196
- def default_ssh_username
197
- 'ubuntu'
198
- end
181
+ if machine_spec.location["is_windows"]
182
+ Chef::Provisioning::Machine::WindowsMachine.new(machine_spec, transport, convergence_strategy)
183
+ else
184
+ Chef::Provisioning::Machine::UnixMachine.new(machine_spec, transport, convergence_strategy)
185
+ end
186
+ end
199
187
 
200
- def vm_for(machine_spec)
201
- if machine_spec.location && machine_spec.name
202
- existing_vms = azure_vm_service.list_virtual_machines
203
- existing_vms.select { |vm| vm.vm_name == machine_spec.name }.first
204
- else
205
- nil
206
- end
207
- end
188
+ def azure_vm_service
189
+ @vm_service ||= Azure::VirtualMachineManagementService.new
190
+ end
208
191
 
209
- def transport_for(machine_spec, machine_options, vm)
210
- if machine_spec.location['is_windows']
211
- create_winrm_transport(machine_spec, machine_options, vm)
212
- else
213
- create_ssh_transport(machine_spec, machine_options, vm)
214
- end
215
- end
192
+ def azure_cloud_service_service
193
+ @cloud_service_service ||= Azure::CloudServiceManagementService.new
194
+ end
216
195
 
217
- def default_image_for_location(location)
218
- Chef::Log.debug("Choosing default image for region '#{location}'")
196
+ def default_ssh_username
197
+ "ubuntu"
198
+ end
219
199
 
220
- case location
221
- when 'East US'
222
- when 'Southeast Asia'
223
- when 'West US'
224
- 'b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04_1-LTS-amd64-server-20140927-en-us-30GB'
225
- else
226
- raise 'Unsupported location!'
227
- end
228
- end
200
+ def vm_for(machine_spec)
201
+ if machine_spec.location && machine_spec.name
202
+ existing_vms = azure_vm_service.list_virtual_machines
203
+ existing_vms.select { |vm| vm.vm_name == machine_spec.name }.first
204
+ else
205
+ nil
206
+ end
207
+ end
229
208
 
230
- def create_ssh_transport(machine_spec, machine_options, vm)
231
- bootstrap_options = machine_options[:bootstrap_options] || {}
232
- username = bootstrap_options[:vm_user] || default_ssh_username
233
- tcp_endpoint = vm.tcp_endpoints.select { |tcp| tcp[:name] == 'SSH' }.first
234
- remote_host = tcp_endpoint[:vip]
209
+ def transport_for(machine_spec, machine_options, vm)
210
+ if machine_spec.location["is_windows"]
211
+ create_winrm_transport(machine_spec, machine_options, vm)
212
+ else
213
+ create_ssh_transport(machine_spec, machine_options, vm)
214
+ end
215
+ end
235
216
 
236
- # TODO: not this... replace with SSH key ASAP, only for getting this thing going...
237
- ssh_options = {
238
- password: machine_options[:password],
239
- port: tcp_endpoint[:public_port] # use public port from Cloud Service endpoint
240
- }
217
+ def default_image_for_location(location)
218
+ Chef::Log.debug("Choosing default image for region '#{location}'")
219
+
220
+ case location
221
+ when "East US"
222
+ when "Southeast Asia"
223
+ when "West US"
224
+ "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04_1-LTS-amd64-server-20140927-en-us-30GB"
225
+ else
226
+ raise "Unsupported location!"
227
+ end
228
+ end
241
229
 
242
- options = {}
243
- options[:prefix] = 'sudo ' if machine_spec.location[:sudo] || username != 'root'
230
+ def create_ssh_transport(machine_spec, machine_options, vm)
231
+ bootstrap_options = machine_options[:bootstrap_options] || {}
232
+ username = bootstrap_options[:vm_user] || default_ssh_username
233
+ tcp_endpoint = vm.tcp_endpoints.select { |tcp| tcp[:name] == "SSH" }.first
234
+ remote_host = tcp_endpoint[:vip]
244
235
 
245
- # Enable pty by default
246
- # TODO: why?
247
- options[:ssh_pty_enable] = true
248
- options[:ssh_gateway] ||= machine_spec.location['ssh_gateway']
236
+ # TODO: not this... replace with SSH key ASAP, only for getting this thing going...
237
+ ssh_options = {
238
+ password: machine_options[:password],
239
+ port: tcp_endpoint[:public_port] # use public port from Cloud Service endpoint
240
+ }
249
241
 
250
- Chef::Provisioning::Transport::SSH.new(remote_host, username, ssh_options, options, config)
251
- end
242
+ options = {}
243
+ options[:prefix] = "sudo " if machine_spec.location[:sudo] || username != "root"
252
244
 
253
- def create_winrm_transport(machine_spec, machine_options, instance)
254
- winrm_transport_options = machine_options[:bootstrap_options][:winrm_transport]
255
- shared_winrm_options = {
256
- :user => machine_options[:vm_user] || 'localadmin',
257
- :pass => machine_options[:password] # TODO: Replace with encryption
258
- }
259
-
260
- if(winrm_transport_options['https'])
261
- tcp_endpoint = instance.tcp_endpoints.select { |tcp| tcp[:name] == 'PowerShell' }.first
262
- remote_host = tcp_endpoint[:vip]
263
- port = tcp_endpoint[:public_port] || default_winrm_https_port
264
- endpoint = "https://#{remote_host}:#{port}/wsman"
265
- type = :ssl
266
- winrm_options = {
267
- :disable_sspi => winrm_transport_options['https'][:disable_sspi] || false, # default to Negotiate
268
- :basic_auth_only => winrm_transport_options['https'][:basic_auth_only] || false, # disallow Basic auth by default
269
- :no_ssl_peer_verification => winrm_transport_options['https'][:no_ssl_peer_verification] || false #disallow MITM potential by default
270
- }
271
- end
245
+ # Enable pty by default
246
+ # TODO: why?
247
+ options[:ssh_pty_enable] = true
248
+ options[:ssh_gateway] ||= machine_spec.location["ssh_gateway"]
272
249
 
273
- if(winrm_transport_options['http'])
274
- tcp_endpoint = instance.tcp_endpoints.select { |tcp| tcp[:name] == 'WinRm-Http' }.first
275
- remote_host = tcp_endpoint[:vip]
276
- port = tcp_endpoint[:public_port] || default_winrm_http_port
277
- endpoint = "http://#{remote_host}:#{port}/wsman"
278
- type = :plaintext
279
- winrm_options = {
280
- :disable_sspi => winrm_transport_options['http']['disable_sspi'] || false, # default to Negotiate
281
- :basic_auth_only => winrm_transport_options['http']['basic_auth_only'] || false # disallow Basic auth by default
282
- }
283
- end
250
+ Chef::Provisioning::Transport::SSH.new(remote_host, username, ssh_options, options, config)
251
+ end
284
252
 
285
- merged_winrm_options = winrm_options.merge(shared_winrm_options)
286
- Chef::Provisioning::Transport::WinRM.new("#{endpoint}", type, merged_winrm_options, {})
287
- end
253
+ def create_winrm_transport(machine_spec, machine_options, instance)
254
+ winrm_transport_options = machine_options[:bootstrap_options][:winrm_transport]
255
+ shared_winrm_options = {
256
+ :user => machine_options[:bootstrap_options][:vm_user] || default_ssh_username,
257
+ :pass => machine_options[:password] # TODO: Replace with encryption
258
+ }
259
+
260
+ if winrm_transport_options["https"]
261
+ tcp_endpoint = instance.tcp_endpoints.select { |tcp| tcp[:name] == "PowerShell" }.first
262
+ remote_host = tcp_endpoint[:vip]
263
+ port = tcp_endpoint[:public_port] || default_winrm_https_port
264
+ endpoint = "https://#{remote_host}:#{port}/wsman"
265
+ type = :ssl
266
+ winrm_options = {
267
+ :disable_sspi => winrm_transport_options["https"][:disable_sspi] || false, # default to Negotiate
268
+ :basic_auth_only => winrm_transport_options["https"][:basic_auth_only] || false, # disallow Basic auth by default
269
+ :no_ssl_peer_verification => winrm_transport_options["https"][:no_ssl_peer_verification] || false #disallow MITM potential by default
270
+ }
271
+ end
272
+
273
+ if winrm_transport_options["http"]
274
+ tcp_endpoint = instance.tcp_endpoints.select { |tcp| tcp[:name] == "WinRm-Http" }.first
275
+ remote_host = tcp_endpoint[:vip]
276
+ port = tcp_endpoint[:public_port] || default_winrm_http_port
277
+ endpoint = "http://#{remote_host}:#{port}/wsman"
278
+ type = :plaintext
279
+ winrm_options = {
280
+ :disable_sspi => winrm_transport_options["http"]["disable_sspi"] || false, # default to Negotiate
281
+ :basic_auth_only => winrm_transport_options["http"]["basic_auth_only"] || false # disallow Basic auth by default
282
+ }
283
+ end
284
+
285
+ merged_winrm_options = winrm_options.merge(shared_winrm_options)
286
+ Chef::Provisioning::Transport::WinRM.new("#{endpoint}", type, merged_winrm_options, {})
287
+ end
288
288
 
289
- def default_winrm_http_port
290
- 5985
291
- end
289
+ def default_winrm_http_port
290
+ 5985
291
+ end
292
292
 
293
- def default_winrm_https_port
294
- 5986
295
- end
293
+ def default_winrm_https_port
294
+ 5986
295
+ end
296
296
 
297
- def convergence_strategy_for(machine_spec, machine_options)
298
- convergence_options = machine_options[:convergence_options]
299
- # Defaults
300
- unless machine_spec.location
301
- return Chef::Provisioning::ConvergenceStrategy::NoConverge.new(convergence_options, config)
302
- end
297
+ def convergence_strategy_for(machine_spec, machine_options)
298
+ convergence_options = machine_options[:convergence_options]
299
+ # Defaults
300
+ unless machine_spec.location
301
+ return Chef::Provisioning::ConvergenceStrategy::NoConverge.new(convergence_options, config)
302
+ end
303
+
304
+ if machine_spec.location["is_windows"]
305
+ Chef::Provisioning::ConvergenceStrategy::InstallMsi.new(convergence_options, config)
306
+ elsif machine_options[:cached_installer]
307
+ Chef::Provisioning::ConvergenceStrategy::InstallCached.new(convergence_options, config)
308
+ else
309
+ Chef::Provisioning::ConvergenceStrategy::InstallSh.new(convergence_options, config)
310
+ end
311
+ end
303
312
 
304
- if machine_spec.location['is_windows']
305
- Chef::Provisioning::ConvergenceStrategy::InstallMsi.new(convergence_options, config)
306
- elsif machine_options[:cached_installer]
307
- Chef::Provisioning::ConvergenceStrategy::InstallCached.new(convergence_options, config)
308
- else
309
- Chef::Provisioning::ConvergenceStrategy::InstallSh.new(convergence_options, config)
310
- end
311
- end
313
+ def wait_until_ready(action_handler, machine_spec)
314
+ vm = vm_for(machine_spec)
312
315
 
313
- def wait_until_ready(action_handler, machine_spec)
314
- vm = vm_for(machine_spec)
316
+ # If the machine is ready, nothing to do
317
+ return if vm.status == "ReadyRole"
315
318
 
316
- # If the machine is ready, nothing to do
317
- return if vm.status == 'ReadyRole'
319
+ # Skip if we don't actually need to do anything
320
+ return unless action_handler.should_perform_actions
318
321
 
319
- # Skip if we don't actually need to do anything
320
- return unless action_handler.should_perform_actions
322
+ time_elapsed = 0
323
+ sleep_time = 10
324
+ max_wait_time = 120
321
325
 
322
- time_elapsed = 0
323
- sleep_time = 10
324
- max_wait_time = 120
326
+ action_handler.report_progress "waiting for #{machine_spec.name} to be ready ..."
327
+ while time_elapsed < 120 && vm.status != "ReadyRole"
328
+ action_handler.report_progress "#{time_elapsed}/#{max_wait_time}s..."
329
+ sleep(sleep_time)
330
+ time_elapsed += sleep_time
331
+ # Azure caches results
332
+ vm = vm_for(machine_spec)
333
+ end
334
+ action_handler.report_progress "#{machine_spec.name} is now ready"
335
+ end
325
336
 
326
- action_handler.report_progress "waiting for #{machine_spec.name} to be ready ..."
327
- while time_elapsed < 120 && vm.status != 'ReadyRole'
328
- action_handler.report_progress "#{time_elapsed}/#{max_wait_time}s..."
329
- sleep(sleep_time)
330
- time_elapsed += sleep_time
331
- # Azure caches results
332
- vm = vm_for(machine_spec)
333
- end
334
- action_handler.report_progress "#{machine_spec.name} is now ready"
335
- end
337
+ def wait_for_transport(action_handler, machine_spec, machine_options)
338
+ vm = vm_for(machine_spec)
339
+ transport = transport_for(machine_spec, machine_options, vm)
336
340
 
337
- def wait_for_transport(action_handler, machine_spec, machine_options)
338
- vm = vm_for(machine_spec)
339
- transport = transport_for(machine_spec, machine_options, vm)
341
+ return if transport.available?
342
+ return unless action_handler.should_perform_actions
340
343
 
341
- return if transport.available?
342
- return unless action_handler.should_perform_actions
344
+ time_elapsed = 0
345
+ sleep_time = 10
346
+ max_wait_time = 120
343
347
 
344
- time_elapsed = 0
345
- sleep_time = 10
346
- max_wait_time = 120
348
+ action_handler.report_progress "Waiting for transport on #{machine_spec.name} ..."
349
+ while time_elapsed < 120 && !transport.available?
350
+ action_handler.report_progress "#{time_elapsed}/#{max_wait_time}s..."
351
+ sleep(sleep_time)
352
+ time_elapsed += sleep_time
353
+ end
354
+ action_handler.report_progress "Transport to #{machine_spec.name} is now up!"
355
+ end
347
356
 
348
- action_handler.report_progress "Waiting for transport on #{machine_spec.name} ..."
349
- while time_elapsed < 120 && !transport.available?
350
- action_handler.report_progress "#{time_elapsed}/#{max_wait_time}s..."
351
- sleep(sleep_time)
352
- time_elapsed += sleep_time
353
357
  end
354
- action_handler.report_progress "Transport to #{machine_spec.name} is now up!"
355
358
  end
356
-
357
359
  end
358
360
  end
359
- end
360
- end