knife-azure 1.8.7 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/azure/azure_interface.rb +79 -81
- data/lib/azure/custom_errors.rb +34 -35
- data/lib/azure/helpers.rb +43 -44
- data/lib/azure/resource_management/ARM_deployment_template.rb +679 -678
- data/lib/azure/resource_management/ARM_interface.rb +513 -515
- data/lib/azure/resource_management/vnet_config.rb +43 -43
- data/lib/azure/resource_management/windows_credentials.rb +181 -184
- data/lib/azure/service_management/ASM_interface.rb +309 -317
- data/lib/azure/service_management/ag.rb +16 -16
- data/lib/azure/service_management/certificate.rb +30 -31
- data/lib/azure/service_management/connection.rb +31 -31
- data/lib/azure/service_management/deploy.rb +40 -38
- data/lib/azure/service_management/disk.rb +14 -10
- data/lib/azure/service_management/host.rb +28 -24
- data/lib/azure/service_management/image.rb +23 -22
- data/lib/azure/service_management/loadbalancer.rb +12 -12
- data/lib/azure/service_management/rest.rb +20 -19
- data/lib/azure/service_management/role.rb +274 -273
- data/lib/azure/service_management/storageaccount.rb +29 -25
- data/lib/azure/service_management/utility.rb +6 -7
- data/lib/azure/service_management/vnet.rb +44 -44
- data/lib/chef/knife/azure_ag_create.rb +18 -18
- data/lib/chef/knife/azure_ag_list.rb +3 -3
- data/lib/chef/knife/azure_base.rb +56 -56
- data/lib/chef/knife/azure_image_list.rb +8 -10
- data/lib/chef/knife/azure_internal-lb_create.rb +15 -15
- data/lib/chef/knife/azure_internal-lb_list.rb +3 -3
- data/lib/chef/knife/azure_server_create.rb +49 -50
- data/lib/chef/knife/azure_server_delete.rb +22 -24
- data/lib/chef/knife/azure_server_list.rb +4 -4
- data/lib/chef/knife/azure_server_show.rb +5 -5
- data/lib/chef/knife/azure_vnet_create.rb +17 -17
- data/lib/chef/knife/azure_vnet_list.rb +3 -3
- data/lib/chef/knife/azurerm_base.rb +58 -60
- data/lib/chef/knife/azurerm_server_create.rb +23 -22
- data/lib/chef/knife/azurerm_server_delete.rb +30 -34
- data/lib/chef/knife/azurerm_server_list.rb +42 -42
- data/lib/chef/knife/azurerm_server_show.rb +1 -1
- data/lib/chef/knife/bootstrap/bootstrap_options.rb +7 -8
- data/lib/chef/knife/bootstrap/bootstrapper.rb +65 -65
- data/lib/chef/knife/bootstrap/common_bootstrap_options.rb +3 -4
- data/lib/chef/knife/bootstrap_azure.rb +13 -13
- data/lib/chef/knife/bootstrap_azurerm.rb +106 -106
- data/lib/knife-azure/version.rb +2 -2
- metadata +43 -76
- data/lib/azure/resource_management/ARM_base.rb +0 -29
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2010-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -20,16 +20,17 @@ module Azure
|
|
20
20
|
class StorageAccounts
|
21
21
|
include AzureUtility
|
22
22
|
def initialize(connection)
|
23
|
-
@connection=connection
|
23
|
+
@connection = connection
|
24
24
|
end
|
25
|
+
|
25
26
|
# force_load should be true when there is something in local cache and we want to reload
|
26
27
|
# first call is always load.
|
27
28
|
def load(force_load = false)
|
28
29
|
if not @azure_storage_accounts || force_load
|
29
30
|
@azure_storage_accounts = begin
|
30
31
|
azure_storage_accounts = Hash.new
|
31
|
-
responseXML = @connection.query_azure(
|
32
|
-
servicesXML = responseXML.css(
|
32
|
+
responseXML = @connection.query_azure("storageservices")
|
33
|
+
servicesXML = responseXML.css("StorageServices StorageService")
|
33
34
|
servicesXML.each do |serviceXML|
|
34
35
|
storage = StorageAccount.new(@connection).parse(serviceXML)
|
35
36
|
azure_storage_accounts[storage.name] = storage
|
@@ -41,13 +42,13 @@ module Azure
|
|
41
42
|
end
|
42
43
|
|
43
44
|
def all
|
44
|
-
|
45
|
+
load.values
|
45
46
|
end
|
46
47
|
|
47
48
|
# first look up local cache if we have already loaded list.
|
48
49
|
def exists?(name)
|
49
50
|
return @azure_storage_accounts.key?(name) if @azure_storage_accounts
|
50
|
-
|
51
|
+
exists_on_cloud?(name)
|
51
52
|
end
|
52
53
|
|
53
54
|
# Look up on cloud and not local cache
|
@@ -55,7 +56,7 @@ module Azure
|
|
55
56
|
ret_val = @connection.query_azure("storageservices/#{name}")
|
56
57
|
error_code, error_message = error_from_response_xml(ret_val) if ret_val
|
57
58
|
if ret_val.nil? || error_code.length > 0
|
58
|
-
Chef::Log.warn
|
59
|
+
Chef::Log.warn "Unable to find storage account:" + error_message + " : " + error_message if ret_val
|
59
60
|
false
|
60
61
|
else
|
61
62
|
true
|
@@ -66,17 +67,18 @@ module Azure
|
|
66
67
|
storage = StorageAccount.new(@connection)
|
67
68
|
storage.create(params)
|
68
69
|
end
|
70
|
+
|
69
71
|
def clear_unattached
|
70
|
-
|
72
|
+
all.each do |storage|
|
71
73
|
next unless storage.attached == false
|
72
|
-
@connection.query_azure(
|
74
|
+
@connection.query_azure("storageaccounts/" + storage.name, "delete")
|
73
75
|
end
|
74
76
|
end
|
75
77
|
|
76
78
|
def delete(name)
|
77
|
-
if
|
78
|
-
|
79
|
-
@connection.query_azure(servicecall, "delete")
|
79
|
+
if exists?(name)
|
80
|
+
servicecall = "storageservices/" + name
|
81
|
+
@connection.query_azure(servicecall, "delete")
|
80
82
|
end
|
81
83
|
end
|
82
84
|
end
|
@@ -90,30 +92,32 @@ module Azure
|
|
90
92
|
def initialize(connection)
|
91
93
|
@connection = connection
|
92
94
|
end
|
95
|
+
|
93
96
|
def parse(serviceXML)
|
94
|
-
@name = xml_content(serviceXML,
|
95
|
-
@description = xml_content(serviceXML,
|
96
|
-
@label = xml_content(serviceXML,
|
97
|
-
@affinitygroup = xml_content(serviceXML,
|
98
|
-
@location = xml_content(serviceXML,
|
99
|
-
@georeplicationenabled = xml_content(serviceXML,
|
100
|
-
@extendpropertyname = xml_content(serviceXML,
|
101
|
-
@extendpropertyvalue = xml_content(serviceXML,
|
97
|
+
@name = xml_content(serviceXML, "ServiceName")
|
98
|
+
@description = xml_content(serviceXML, "Description")
|
99
|
+
@label = xml_content(serviceXML, "Label")
|
100
|
+
@affinitygroup = xml_content(serviceXML, "AffinityGroup")
|
101
|
+
@location = xml_content(serviceXML, "Location")
|
102
|
+
@georeplicationenabled = xml_content(serviceXML, "GeoReplicationEnabled")
|
103
|
+
@extendpropertyname = xml_content(serviceXML, "ExtendedProperties ExtendedProperty Name")
|
104
|
+
@extendpropertyvalue = xml_content(serviceXML, "ExtendedProperties ExtendedProperty Value")
|
102
105
|
self
|
103
106
|
end
|
107
|
+
|
104
108
|
def create(params)
|
105
109
|
builder = Nokogiri::XML::Builder.new do |xml|
|
106
|
-
xml.CreateStorageServiceInput(
|
110
|
+
xml.CreateStorageServiceInput("xmlns" => "http://schemas.microsoft.com/windowsazure") do
|
107
111
|
xml.ServiceName params[:azure_storage_account]
|
108
112
|
xml.Label Base64.encode64(params[:azure_storage_account])
|
109
|
-
xml.Description params[:azure_storage_account_description] ||
|
113
|
+
xml.Description params[:azure_storage_account_description] || "Explicitly created storage service"
|
110
114
|
# Location defaults to 'West US'
|
111
115
|
if params[:azure_affinity_group]
|
112
116
|
xml.AffinityGroup params[:azure_affinity_group]
|
113
|
-
else
|
114
|
-
xml.Location params[:azure_service_location] ||
|
117
|
+
else
|
118
|
+
xml.Location params[:azure_service_location] || "West US"
|
115
119
|
end
|
116
|
-
|
120
|
+
end
|
117
121
|
end
|
118
122
|
@connection.query_azure("storageservices", "post", builder.to_xml)
|
119
123
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2010-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,7 +17,7 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
module AzureUtility
|
20
|
-
def xml_content(xml, key, default=
|
20
|
+
def xml_content(xml, key, default = "")
|
21
21
|
content = default
|
22
22
|
node = xml.at_css(key)
|
23
23
|
if node
|
@@ -27,15 +27,14 @@ module AzureUtility
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def error_from_response_xml(response_xml)
|
30
|
-
error_code_and_message = [
|
31
|
-
error_node = response_xml.at_css(
|
30
|
+
error_code_and_message = ["", ""]
|
31
|
+
error_node = response_xml.at_css("Error")
|
32
32
|
|
33
33
|
if error_node
|
34
|
-
error_code_and_message[0] = xml_content(error_node,
|
35
|
-
error_code_and_message[1] = xml_content(error_node,
|
34
|
+
error_code_and_message[0] = xml_content(error_node, "Code")
|
35
|
+
error_code_and_message[1] = xml_content(error_node, "Message")
|
36
36
|
end
|
37
37
|
|
38
38
|
error_code_and_message
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Jeff Mendoza (jeffmendoza@live.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2013-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -25,8 +25,8 @@ module Azure
|
|
25
25
|
def load
|
26
26
|
@vnets ||= begin
|
27
27
|
@vnets = {}
|
28
|
-
response = @connection.query_azure(
|
29
|
-
response.css(
|
28
|
+
response = @connection.query_azure("networking/virtualnetwork")
|
29
|
+
response.css("VirtualNetworkSite").each do |vnet|
|
30
30
|
item = Vnet.new(@connection).parse(vnet)
|
31
31
|
@vnets[item.name] = item
|
32
32
|
end
|
@@ -62,73 +62,73 @@ module Azure
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def parse(image)
|
65
|
-
@name = image.at_css(
|
66
|
-
@affinity_group = image.at_css(
|
67
|
-
@state = image.at_css(
|
65
|
+
@name = image.at_css("Name").content
|
66
|
+
@affinity_group = image.at_css("AffinityGroup") ? image.at_css("AffinityGroup").content : ""
|
67
|
+
@state = image.at_css("State").content
|
68
68
|
self
|
69
69
|
end
|
70
70
|
|
71
71
|
def create(params)
|
72
|
-
response = @connection.query_azure(
|
73
|
-
if response.at_css("Error") && response.at_css(
|
72
|
+
response = @connection.query_azure("networking/media")
|
73
|
+
if response.at_css("Error") && response.at_css("Code").text == "ResourceNotFound"
|
74
74
|
builder = Nokogiri::XML::Builder.new do |xml|
|
75
75
|
xml.NetworkConfiguration(
|
76
|
-
|
77
|
-
)
|
76
|
+
"xmlns" => "http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration"
|
77
|
+
) do
|
78
78
|
|
79
|
-
xml.VirtualNetworkConfiguration
|
80
|
-
xml.VirtualNetworkSites
|
81
|
-
xml.VirtualNetworkSite(
|
79
|
+
xml.VirtualNetworkConfiguration do
|
80
|
+
xml.VirtualNetworkSites do
|
81
|
+
xml.VirtualNetworkSite("name" => params[:azure_vnet_name], "AffinityGroup" => params[:azure_ag_name]) do
|
82
82
|
if params[:azure_address_space]
|
83
|
-
xml.AddressSpace
|
83
|
+
xml.AddressSpace do
|
84
84
|
xml.AddressPrefix params[:azure_address_space]
|
85
|
-
|
85
|
+
end
|
86
86
|
end
|
87
|
-
xml.Subnets
|
88
|
-
xml.Subnet(
|
87
|
+
xml.Subnets do
|
88
|
+
xml.Subnet("name" => params[:azure_subnet_name]) do
|
89
89
|
xml.AddressPrefix params[:azure_address_space]
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
96
|
end
|
97
97
|
puts("Creating New Virtual Network: #{params[:azure_vnet_name]}...")
|
98
98
|
response = builder
|
99
99
|
else
|
100
|
-
vnets = response.css(
|
100
|
+
vnets = response.css("VirtualNetworkSite")
|
101
101
|
vnet = nil
|
102
|
-
vnets.each { |vn| vnet = vn if vn[
|
102
|
+
vnets.each { |vn| vnet = vn if vn["name"] == params[:azure_vnet_name] }
|
103
103
|
add = vnet.nil?
|
104
|
-
vnet = Nokogiri::XML::Node.new(
|
105
|
-
vnet[
|
106
|
-
vnet[
|
107
|
-
if add || !vnet.at_css(
|
108
|
-
addr_space = Nokogiri::XML::Node.new(
|
109
|
-
else
|
110
|
-
addr_space = vnet.at_css(
|
104
|
+
vnet = Nokogiri::XML::Node.new("VirtualNetworkSite", response) if add
|
105
|
+
vnet["name"] = params[:azure_vnet_name]
|
106
|
+
vnet["AffinityGroup"] = params[:azure_ag_name]
|
107
|
+
if add || !vnet.at_css("AddressSpace") ## create a new AddressSpace block in XML if VNet or AddressSpace block does not already exist
|
108
|
+
addr_space = Nokogiri::XML::Node.new("AddressSpace", response)
|
109
|
+
else ## retrieve object of existing AddressSpace if VNet or AddressSpace already exist
|
110
|
+
addr_space = vnet.at_css("AddressSpace")
|
111
111
|
end
|
112
|
-
addr_prefix = Nokogiri::XML::Node.new(
|
112
|
+
addr_prefix = Nokogiri::XML::Node.new("AddressPrefix", response)
|
113
113
|
addr_prefix.content = params[:azure_address_space]
|
114
|
-
if add || !vnet.at_css(
|
115
|
-
subnets = Nokogiri::XML::Node.new(
|
116
|
-
else
|
117
|
-
subnets = vnet.at_css(
|
114
|
+
if add || !vnet.at_css("Subnets") ## create a new Subnets block in XML if VNet or Subnets block does not already exist
|
115
|
+
subnets = Nokogiri::XML::Node.new("Subnets", response)
|
116
|
+
else ## retrieve object of existing Subnets if VNet or Subnets already exist
|
117
|
+
subnets = vnet.at_css("Subnets")
|
118
118
|
end
|
119
|
-
saddr_prefix = Nokogiri::XML::Node.new(
|
119
|
+
saddr_prefix = Nokogiri::XML::Node.new("AddressPrefix", response)
|
120
120
|
saddr_prefix.content = params[:azure_address_space]
|
121
|
-
subnet = Nokogiri::XML::Node.new(
|
122
|
-
subnet[
|
121
|
+
subnet = Nokogiri::XML::Node.new("Subnet", response)
|
122
|
+
subnet["name"] = params[:azure_subnet_name]
|
123
123
|
subnet.children = saddr_prefix
|
124
124
|
subnets.children = subnet
|
125
|
-
vnet.add_child(subnets) if add || !vnet.at_css(
|
125
|
+
vnet.add_child(subnets) if add || !vnet.at_css("Subnets")
|
126
126
|
addr_space.children = addr_prefix
|
127
|
-
vnet.add_child(addr_space) if add || !vnet.at_css(
|
127
|
+
vnet.add_child(addr_space) if add || !vnet.at_css("AddressSpace")
|
128
128
|
vnets.last.add_next_sibling(vnet) if add
|
129
129
|
puts("Updating existing Virtual Network: #{params[:azure_vnet_name]}...")
|
130
130
|
end
|
131
|
-
@connection.query_azure(
|
131
|
+
@connection.query_azure("networking/media", "put", response.to_xml)
|
132
132
|
end
|
133
133
|
end
|
134
|
-
end
|
134
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Jeff Mendoza (jeffmendoza@live.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2013-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -16,36 +16,36 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require File.expand_path(
|
19
|
+
require File.expand_path("../azure_base", __FILE__)
|
20
20
|
|
21
21
|
class Chef
|
22
22
|
class Knife
|
23
23
|
class AzureAgCreate < Knife
|
24
24
|
include Knife::AzureBase
|
25
25
|
|
26
|
-
banner
|
26
|
+
banner "knife azure ag create (options)"
|
27
27
|
|
28
28
|
option :azure_affinity_group,
|
29
|
-
:short =>
|
30
|
-
:long =>
|
31
|
-
:description =>
|
29
|
+
:short => "-a GROUP",
|
30
|
+
:long => "--azure-affinity-group GROUP",
|
31
|
+
:description => "Specifies new affinity group name."
|
32
32
|
|
33
33
|
option :azure_ag_desc,
|
34
|
-
:long =>
|
35
|
-
:description =>
|
34
|
+
:long => "--azure-ag-desc DESC",
|
35
|
+
:description => "Optional. Description for new affinity group."
|
36
36
|
|
37
37
|
option :azure_service_location,
|
38
|
-
:short =>
|
39
|
-
:long =>
|
40
|
-
:description =>
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
:short => "-m LOCATION",
|
39
|
+
:long => "--azure-service-location LOCATION",
|
40
|
+
:description => "Specifies the geographic location - the name of "\
|
41
|
+
"the data center location that is valid for your "\
|
42
|
+
"subscription. Eg: West US, East US, "\
|
43
|
+
"East Asia, Southeast Asia, North Europe, West Europe"
|
44
44
|
|
45
45
|
def run
|
46
46
|
$stdout.sync = true
|
47
47
|
|
48
|
-
Chef::Log.info(
|
48
|
+
Chef::Log.info("validating...")
|
49
49
|
validate_asm_keys!(:azure_affinity_group,
|
50
50
|
:azure_service_location)
|
51
51
|
|
@@ -57,9 +57,9 @@ class Chef
|
|
57
57
|
|
58
58
|
rsp = service.create_affinity_group(params)
|
59
59
|
print "\n"
|
60
|
-
if rsp.at_css(
|
61
|
-
if rsp.at_css(
|
62
|
-
puts
|
60
|
+
if rsp.at_css("Status").nil?
|
61
|
+
if rsp.at_css("Code").nil? || rsp.at_css("Message").nil?
|
62
|
+
puts "Unknown Error. try -VV"
|
63
63
|
else
|
64
64
|
puts "#{rsp.at_css('Code').content}: "\
|
65
65
|
"#{rsp.at_css('Message').content}"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Jeff Mendoza (jeffmendoza@live.com)
|
3
|
-
# Copyright:: Copyright
|
3
|
+
# Copyright:: Copyright 2013-2018 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -16,14 +16,14 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require File.expand_path(
|
19
|
+
require File.expand_path("../azure_base", __FILE__)
|
20
20
|
|
21
21
|
class Chef
|
22
22
|
class Knife
|
23
23
|
class AzureAgList < Knife
|
24
24
|
include Knife::AzureBase
|
25
25
|
|
26
|
-
banner
|
26
|
+
banner "knife azure ag list (options)"
|
27
27
|
|
28
28
|
def run
|
29
29
|
$stdout.sync = true
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
# Author:: Barry Davis (barryd@jetstreamsoftware.com)
|
3
|
-
# Author:: Seth Chisamore (<schisamo@
|
4
|
-
# Copyright:: Copyright
|
3
|
+
# Author:: Seth Chisamore (<schisamo@chef.io>)
|
4
|
+
# Copyright:: Copyright 2011-2018 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,8 +17,8 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
20
|
+
require "chef/knife"
|
21
|
+
require "azure/service_management/ASM_interface"
|
22
22
|
|
23
23
|
class Chef
|
24
24
|
class Knife
|
@@ -31,8 +31,8 @@ class Chef
|
|
31
31
|
includer.class_eval do
|
32
32
|
|
33
33
|
deps do
|
34
|
-
require
|
35
|
-
require
|
34
|
+
require "readline"
|
35
|
+
require "chef/json_compat"
|
36
36
|
end
|
37
37
|
|
38
38
|
option :azure_subscription_id,
|
@@ -70,7 +70,7 @@ class Chef
|
|
70
70
|
images = service.list_images
|
71
71
|
target_image = images.select { |i| i.name == locate_config_value(:azure_source_image) }
|
72
72
|
unless target_image[0].nil?
|
73
|
-
return target_image[0].os ==
|
73
|
+
return target_image[0].os == "Windows"
|
74
74
|
else
|
75
75
|
ui.error("Invalid image. Use the command \"knife azure image list\" to verify the image name")
|
76
76
|
exit 1
|
@@ -95,7 +95,7 @@ class Chef
|
|
95
95
|
config[key] || Chef::Config[:knife][key]
|
96
96
|
end
|
97
97
|
|
98
|
-
def msg_pair(label, value, color
|
98
|
+
def msg_pair(label, value, color = :cyan)
|
99
99
|
if value && !value.to_s.empty?
|
100
100
|
puts "#{ui.color(label, color)}: #{value}"
|
101
101
|
end
|
@@ -103,24 +103,24 @@ class Chef
|
|
103
103
|
|
104
104
|
def msg_server_summary(server)
|
105
105
|
puts "\n"
|
106
|
-
msg_pair(
|
107
|
-
msg_pair(
|
108
|
-
msg_pair(
|
109
|
-
msg_pair(
|
110
|
-
msg_pair(
|
111
|
-
msg_pair(
|
112
|
-
msg_pair(
|
113
|
-
msg_pair(
|
114
|
-
msg_pair(
|
115
|
-
msg_pair(
|
116
|
-
msg_pair(
|
117
|
-
msg_pair(
|
118
|
-
msg_pair(
|
106
|
+
msg_pair("DNS Name", server.hostedservicename + ".cloudapp.net")
|
107
|
+
msg_pair("VM Name", server.name)
|
108
|
+
msg_pair("Size", server.size)
|
109
|
+
msg_pair("Azure Source Image", locate_config_value(:azure_source_image))
|
110
|
+
msg_pair("Azure Service Location", locate_config_value(:azure_service_location))
|
111
|
+
msg_pair("Public Ip Address", server.publicipaddress)
|
112
|
+
msg_pair("Private Ip Address", server.ipaddress)
|
113
|
+
msg_pair("SSH Port", server.sshport) unless server.sshport.nil?
|
114
|
+
msg_pair("WinRM Port", server.winrmport) unless server.winrmport.nil?
|
115
|
+
msg_pair("TCP Ports", server.tcpports) unless server.tcpports.nil? || server.tcpports.empty?
|
116
|
+
msg_pair("UDP Ports", server.udpports) unless server.udpports.nil? || server.udpports.empty?
|
117
|
+
msg_pair("Environment", locate_config_value(:environment) || "_default")
|
118
|
+
msg_pair("Runlist", locate_config_value(:run_list)) unless locate_config_value(:run_list).empty?
|
119
119
|
puts "\n"
|
120
120
|
end
|
121
121
|
|
122
122
|
def pretty_key(key)
|
123
|
-
key.to_s.
|
123
|
+
key.to_s.tr("_", " ").gsub(/\w+/) { |w| (w =~ /(ssh)|(aws)/i) ? w.upcase : w.capitalize }
|
124
124
|
end
|
125
125
|
|
126
126
|
# validate command pre-requisites (cli options)
|
@@ -172,12 +172,12 @@ class Chef
|
|
172
172
|
exit 1
|
173
173
|
end
|
174
174
|
|
175
|
-
if locate_config_value(:extended_logs) && locate_config_value(:bootstrap_protocol) !=
|
175
|
+
if locate_config_value(:extended_logs) && locate_config_value(:bootstrap_protocol) != "cloud-api"
|
176
176
|
ui.error("--extended-logs option only works with --bootstrap-protocol cloud-api")
|
177
177
|
exit 1
|
178
178
|
end
|
179
179
|
|
180
|
-
if locate_config_value(:bootstrap_protocol) ==
|
180
|
+
if locate_config_value(:bootstrap_protocol) == "cloud-api" && locate_config_value(:azure_vm_name).nil? && locate_config_value(:azure_dns_name).nil?
|
181
181
|
ui.error("Specifying the DNS name using --azure-dns-name or VM name using --azure-vm-name option is required with --bootstrap-protocol cloud-api")
|
182
182
|
exit 1
|
183
183
|
end
|
@@ -187,7 +187,7 @@ class Chef
|
|
187
187
|
raise ArgumentError, "The daemon option is only supported for Windows nodes."
|
188
188
|
end
|
189
189
|
|
190
|
-
unless locate_config_value(:bootstrap_protocol) ==
|
190
|
+
unless locate_config_value(:bootstrap_protocol) == "cloud-api"
|
191
191
|
raise ArgumentError, "The --daemon option requires the use of --bootstrap-protocol cloud-api"
|
192
192
|
end
|
193
193
|
|
@@ -205,7 +205,7 @@ class Chef
|
|
205
205
|
errors << "You did not provide a valid '#{pretty_key(k)}' value. Please set knife[:#{k}] in your knife.rb or pass as an option."
|
206
206
|
end
|
207
207
|
end
|
208
|
-
if errors.each{|e| ui.error(e)}.any?
|
208
|
+
if errors.each { |e| ui.error(e) }.any?
|
209
209
|
exit 1
|
210
210
|
end
|
211
211
|
end
|
@@ -215,11 +215,11 @@ class Chef
|
|
215
215
|
mandatory_keys = [:azure_subscription_id, :azure_mgmt_cert, :azure_api_host_name]
|
216
216
|
keys.concat(mandatory_keys)
|
217
217
|
|
218
|
-
if
|
218
|
+
if !locate_config_value(:azure_mgmt_cert).nil?
|
219
219
|
config[:azure_mgmt_cert] = File.read find_file(locate_config_value(:azure_mgmt_cert))
|
220
220
|
end
|
221
221
|
|
222
|
-
if
|
222
|
+
if !locate_config_value(:azure_publish_settings_file).nil?
|
223
223
|
parse_publish_settings_file(locate_config_value(:azure_publish_settings_file))
|
224
224
|
elsif locate_config_value(:azure_subscription_id).nil? && locate_config_value(:azure_mgmt_cert).nil? && locate_config_value(:azure_api_host_name).nil?
|
225
225
|
azureprofile_file = get_azure_profile_file_path
|
@@ -231,10 +231,10 @@ class Chef
|
|
231
231
|
end
|
232
232
|
|
233
233
|
def parse_publish_settings_file(filename)
|
234
|
-
require
|
235
|
-
require
|
236
|
-
require
|
237
|
-
require
|
234
|
+
require "nokogiri"
|
235
|
+
require "base64"
|
236
|
+
require "openssl"
|
237
|
+
require "uri"
|
238
238
|
begin
|
239
239
|
doc = Nokogiri::XML(File.open(find_file(filename)))
|
240
240
|
profile = doc.at_css("PublishProfile")
|
@@ -258,23 +258,23 @@ class Chef
|
|
258
258
|
end
|
259
259
|
|
260
260
|
def get_azure_profile_file_path
|
261
|
-
|
261
|
+
"~/.azure/azureProfile.json"
|
262
262
|
end
|
263
263
|
|
264
264
|
def parse_azure_profile(filename, errors)
|
265
|
-
require
|
266
|
-
require
|
265
|
+
require "openssl"
|
266
|
+
require "uri"
|
267
267
|
errors = [] if errors.nil?
|
268
268
|
azure_profile = File.read(File.expand_path(filename))
|
269
269
|
azure_profile = JSON.parse(azure_profile)
|
270
270
|
default_subscription = get_default_subscription(azure_profile)
|
271
|
-
if default_subscription.has_key?(
|
271
|
+
if default_subscription.has_key?("id") && default_subscription.has_key?("managementCertificate") && default_subscription.has_key?("managementEndpointUrl")
|
272
272
|
|
273
|
-
Chef::Config[:knife][:azure_subscription_id] = default_subscription[
|
274
|
-
mgmt_key = OpenSSL::PKey::RSA.new(default_subscription[
|
275
|
-
mgmt_cert = OpenSSL::X509::Certificate.new(default_subscription[
|
273
|
+
Chef::Config[:knife][:azure_subscription_id] = default_subscription["id"]
|
274
|
+
mgmt_key = OpenSSL::PKey::RSA.new(default_subscription["managementCertificate"]["key"]).to_pem
|
275
|
+
mgmt_cert = OpenSSL::X509::Certificate.new(default_subscription["managementCertificate"]["cert"]).to_pem
|
276
276
|
Chef::Config[:knife][:azure_mgmt_cert] = mgmt_key + mgmt_cert
|
277
|
-
Chef::Config[:knife][:azure_api_host_name] = URI(default_subscription[
|
277
|
+
Chef::Config[:knife][:azure_api_host_name] = URI(default_subscription["managementEndpointUrl"]).host
|
278
278
|
else
|
279
279
|
errors << "Check if values set for 'id', 'managementCertificate', 'managementEndpointUrl' in -> #{filename} for 'defaultSubscription'. \n OR "
|
280
280
|
end
|
@@ -283,8 +283,8 @@ class Chef
|
|
283
283
|
|
284
284
|
def get_default_subscription(azure_profile)
|
285
285
|
first_subscription_as_default = nil
|
286
|
-
azure_profile[
|
287
|
-
if subscription[
|
286
|
+
azure_profile["subscriptions"].each do |subscription|
|
287
|
+
if subscription["isDefault"]
|
288
288
|
Chef::Log.info("Default subscription \'#{subscription['name']}\'' selected.")
|
289
289
|
return subscription
|
290
290
|
end
|
@@ -295,7 +295,7 @@ class Chef
|
|
295
295
|
if first_subscription_as_default
|
296
296
|
Chef::Log.info("First subscription \'#{subscription['name']}\' selected as default.")
|
297
297
|
else
|
298
|
-
Chef::Log.info(
|
298
|
+
Chef::Log.info("No subscriptions found.")
|
299
299
|
exit 1
|
300
300
|
end
|
301
301
|
first_subscription_as_default
|
@@ -308,10 +308,10 @@ class Chef
|
|
308
308
|
file = name
|
309
309
|
elsif config_dir && File.exist?(File.join(config_dir, name))
|
310
310
|
file = File.join(config_dir, name)
|
311
|
-
elsif File.exist?(File.join(ENV[
|
312
|
-
file = File.join(ENV[
|
311
|
+
elsif File.exist?(File.join(ENV["HOME"], ".chef", name))
|
312
|
+
file = File.join(ENV["HOME"], ".chef", name)
|
313
313
|
else
|
314
|
-
ui.error(
|
314
|
+
ui.error("Unable to find file - " + name)
|
315
315
|
exit 1
|
316
316
|
end
|
317
317
|
file
|
@@ -327,15 +327,15 @@ class Chef
|
|
327
327
|
def fetch_role
|
328
328
|
deployment = fetch_deployment
|
329
329
|
|
330
|
-
if deployment.at_css(
|
331
|
-
role_list_xml =
|
330
|
+
if deployment.at_css("Deployment Name") != nil
|
331
|
+
role_list_xml = deployment.css("RoleInstanceList RoleInstance")
|
332
332
|
role_list_xml.each do |role|
|
333
333
|
if role.at_css("RoleName").text == (locate_config_value(:azure_vm_name) || @name_args[0])
|
334
334
|
return role
|
335
335
|
end
|
336
336
|
end
|
337
337
|
end
|
338
|
-
|
338
|
+
nil
|
339
339
|
end
|
340
340
|
|
341
341
|
def fetch_extension(role)
|
@@ -347,7 +347,7 @@ class Chef
|
|
347
347
|
return ext
|
348
348
|
end
|
349
349
|
end
|
350
|
-
|
350
|
+
nil
|
351
351
|
end
|
352
352
|
|
353
353
|
def fetch_substatus(extension)
|
@@ -358,19 +358,19 @@ class Chef
|
|
358
358
|
return substatus
|
359
359
|
end
|
360
360
|
end
|
361
|
-
|
361
|
+
nil
|
362
362
|
end
|
363
363
|
|
364
364
|
def fetch_chef_client_logs(fetch_process_start_time, fetch_process_wait_timeout)
|
365
365
|
## fetch server details ##
|
366
366
|
role = fetch_role
|
367
|
-
if role
|
367
|
+
if !role.nil?
|
368
368
|
## fetch Chef Extension details deployed on the server ##
|
369
369
|
ext = fetch_extension(role)
|
370
|
-
if ext
|
370
|
+
if !ext.nil?
|
371
371
|
## fetch substatus field which contains the chef-client run logs ##
|
372
372
|
substatus = fetch_substatus(ext)
|
373
|
-
if substatus
|
373
|
+
if !substatus.nil?
|
374
374
|
## chef-client run logs becomes available ##
|
375
375
|
name = substatus.at_css("Name").text
|
376
376
|
status = substatus.at_css("Status").text
|
@@ -393,11 +393,11 @@ class Chef
|
|
393
393
|
end
|
394
394
|
puts "#{ui.color(status, color, :bold)}"
|
395
395
|
puts "----> chef-client run logs: "
|
396
|
-
puts "\n#{message}\n"
|
396
|
+
puts "\n#{message}\n" ## message field of substatus contains the chef-client run logs ##
|
397
397
|
else
|
398
398
|
## unavailability of the substatus field indicates that chef-client run is not completed yet on the server ##
|
399
399
|
fetch_process_wait_time = ((Time.now - fetch_process_start_time) / 60).round
|
400
|
-
if fetch_process_wait_time <= fetch_process_wait_timeout
|
400
|
+
if fetch_process_wait_time <= fetch_process_wait_timeout ## wait for maximum 30 minutes until chef-client run logs becomes available ##
|
401
401
|
print "#{ui.color('.', :bold)}"
|
402
402
|
sleep 30
|
403
403
|
fetch_chef_client_logs(fetch_process_start_time, fetch_process_wait_timeout)
|