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 +4 -4
- data/Gemfile +3 -1
- data/README.md +25 -24
- data/chef-provisioning-azure.gemspec +25 -24
- data/lib/chef/provider/azure_cloud_service.rb +1 -1
- data/lib/chef/provider/azure_sql_server.rb +5 -5
- data/lib/chef/provider/azure_storage_account.rb +1 -1
- data/lib/chef/provisioning/azure_driver.rb +3 -3
- data/lib/chef/provisioning/azure_driver/azure_provider.rb +5 -5
- data/lib/chef/provisioning/azure_driver/azure_resource.rb +4 -4
- data/lib/chef/provisioning/azure_driver/bootstrap_options.rb +18 -18
- data/lib/chef/provisioning/azure_driver/constants.rb +29 -29
- data/lib/chef/provisioning/azure_driver/driver.rb +315 -315
- data/lib/chef/provisioning/azure_driver/machine_options.rb +43 -43
- data/lib/chef/provisioning/azure_driver/resources.rb +1 -1
- data/lib/chef/provisioning/azure_driver/subscriptions.rb +201 -201
- data/lib/chef/provisioning/azure_driver/version.rb +5 -5
- data/lib/chef/provisioning/driver_init/azure.rb +2 -2
- data/lib/chef/resource/azure_cloud_service.rb +2 -2
- data/lib/chef/resource/azure_sql_server.rb +2 -2
- data/lib/chef/resource/azure_storage_account.rb +2 -2
- metadata +26 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4dc56508086b8397f5e1e4eab691392011eca2bb
|
4
|
+
data.tar.gz: a77798d891a143c7d2a2d7d30cbd662d09d2e33e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7997caedf65e4e61cc99dad763aa33d455aef004fb3f4faacce780b00d9497dd54f462be804132900757f830f6d3d7566c57bf7a1b9ddd48af929b71d8d945d2
|
7
|
+
data.tar.gz: 2b5388bea4b4b3cda7c95b5a7bbf85088c1a522992163f0067d0f0eafdc106829f7e61df20d1d0a04076555f7425215478f110652a5fd415f8ae74878aab4b9f
|
data/Gemfile
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
source
|
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
|
-
[](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
|
+
[](https://travis-ci.org/chef/chef-provisioning-azure) [](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
|
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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
-
|
106
|
-
|
107
|
-
|
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__) +
|
2
|
-
require
|
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 =
|
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
|
9
|
-
s.summary =
|
10
|
-
|
11
|
-
s.description =
|
12
|
-
|
13
|
-
s.author =
|
14
|
-
s.email =
|
15
|
-
s.homepage =
|
16
|
-
s.license =
|
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
|
19
|
-
s.add_dependency
|
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
|
22
|
-
s.add_development_dependency
|
23
|
-
s.add_development_dependency
|
24
|
-
s.add_development_dependency
|
25
|
-
s.add_development_dependency
|
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 =
|
28
|
-
s.executables = %w
|
28
|
+
s.bindir = "bin"
|
29
|
+
s.executables = %w{ }
|
29
30
|
|
30
|
-
s.require_path =
|
31
|
-
s.files = %w
|
32
|
-
s.files += Dir.glob(
|
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
|
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 |
|
18
|
-
rule_name = URI
|
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
|
-
|
32
|
+
raise "Destroy not yet implemented on Azure SQL Server using ASM."
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "chef/provisioning"
|
2
|
+
require "chef/provisioning/azure_driver/driver"
|
3
|
+
require "chef/provisioning/azure_driver/resources"
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
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
|
-
|
15
|
+
"https://management.database.windows.net:8443"
|
16
16
|
end
|
17
17
|
|
18
18
|
def action_handler
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
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(
|
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
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
12
|
-
|
11
|
+
# @return [String] The VM user
|
12
|
+
attr_accessor :vm_user
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
# @return [String] The identifier for the VM image to use
|
15
|
+
attr_accessor :image
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
# @return [String] the password to use
|
18
|
+
attr_accessor :password
|
19
19
|
|
20
|
-
|
21
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
|
13
|
-
require
|
14
|
-
require
|
15
|
-
|
16
|
-
require
|
17
|
-
require
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
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
|
-
|
160
|
-
|
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
|
-
|
163
|
-
|
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
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
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
|
-
|
159
|
+
# Check if we need to proceed
|
160
|
+
return if vm.nil? || vm_name.nil? || cloud_service.nil?
|
172
161
|
|
173
|
-
|
174
|
-
|
162
|
+
# Skip if we don't actually need to do anything
|
163
|
+
return unless action_handler.should_perform_actions
|
175
164
|
|
176
|
-
|
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
|
-
|
179
|
-
convergence_strategy = convergence_strategy_for(machine_spec, machine_options)
|
171
|
+
private
|
180
172
|
|
181
|
-
|
182
|
-
|
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
|
-
|
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
|
-
|
193
|
-
|
194
|
-
end
|
178
|
+
transport = transport_for(machine_spec, machine_options, vm)
|
179
|
+
convergence_strategy = convergence_strategy_for(machine_spec, machine_options)
|
195
180
|
|
196
|
-
|
197
|
-
|
198
|
-
|
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
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
210
|
-
|
211
|
-
|
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
|
-
|
218
|
-
|
196
|
+
def default_ssh_username
|
197
|
+
"ubuntu"
|
198
|
+
end
|
219
199
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
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
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
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
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
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
|
-
|
243
|
-
|
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
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
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
|
-
|
251
|
-
|
242
|
+
options = {}
|
243
|
+
options[:prefix] = "sudo " if machine_spec.location[:sudo] || username != "root"
|
252
244
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
:
|
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
|
-
|
274
|
-
|
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
|
-
|
286
|
-
|
287
|
-
|
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
|
-
|
290
|
-
|
291
|
-
|
289
|
+
def default_winrm_http_port
|
290
|
+
5985
|
291
|
+
end
|
292
292
|
|
293
|
-
|
294
|
-
|
295
|
-
|
293
|
+
def default_winrm_https_port
|
294
|
+
5986
|
295
|
+
end
|
296
296
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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
|
-
|
305
|
-
|
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
|
-
|
314
|
-
|
316
|
+
# If the machine is ready, nothing to do
|
317
|
+
return if vm.status == "ReadyRole"
|
315
318
|
|
316
|
-
|
317
|
-
|
319
|
+
# Skip if we don't actually need to do anything
|
320
|
+
return unless action_handler.should_perform_actions
|
318
321
|
|
319
|
-
|
320
|
-
|
322
|
+
time_elapsed = 0
|
323
|
+
sleep_time = 10
|
324
|
+
max_wait_time = 120
|
321
325
|
|
322
|
-
|
323
|
-
|
324
|
-
|
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
|
-
|
327
|
-
|
328
|
-
|
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
|
-
|
338
|
-
|
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
|
-
|
342
|
-
|
344
|
+
time_elapsed = 0
|
345
|
+
sleep_time = 10
|
346
|
+
max_wait_time = 120
|
343
347
|
|
344
|
-
|
345
|
-
|
346
|
-
|
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
|