chef-provisioning-azure 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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