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 +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
|
-
[![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
|
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
|