knife-azure 1.8.7 → 1.9.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/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)
|