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,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Aliasgar Batterywala (aliasgar.batterywala@clogeny.com)
|
3
3
|
#
|
4
|
-
# Copyright:: Copyright
|
4
|
+
# Copyright:: Copyright 2016-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,7 +17,7 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
20
|
+
require "ipaddress"
|
21
21
|
|
22
22
|
module Azure::ARM
|
23
23
|
module VnetConfig
|
@@ -37,16 +37,14 @@ module Azure::ARM
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def get_vnet(resource_group_name, vnet_name)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
raise error
|
49
|
-
end
|
40
|
+
network_resource_client.virtual_networks.get(resource_group_name, vnet_name)
|
41
|
+
rescue MsRestAzure::AzureOperationError => error
|
42
|
+
if error.body
|
43
|
+
err_json = JSON.parse(error.response.body)
|
44
|
+
if err_json["error"]["code"] == "ResourceNotFound"
|
45
|
+
return false
|
46
|
+
else
|
47
|
+
raise error
|
50
48
|
end
|
51
49
|
end
|
52
50
|
end
|
@@ -60,9 +58,9 @@ module Azure::ARM
|
|
60
58
|
## single subnet body creation to be added in template ##
|
61
59
|
def subnet(subnet_name, subnet_prefix)
|
62
60
|
{
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
"name" => subnet_name,
|
62
|
+
"properties" => {
|
63
|
+
"addressPrefix" => subnet_prefix
|
66
64
|
}
|
67
65
|
}
|
68
66
|
end
|
@@ -81,7 +79,7 @@ module Azure::ARM
|
|
81
79
|
## IP address to allocate the network for the new subnet to be added in the
|
82
80
|
## existing virtual network ##
|
83
81
|
def sort_available_networks(available_networks)
|
84
|
-
available_networks.sort_by { |nwrk| nwrk.network.address.split(
|
82
|
+
available_networks.sort_by { |nwrk| nwrk.network.address.split(".").map(&:to_i) }
|
85
83
|
end
|
86
84
|
|
87
85
|
## sort existing subnets in ascending order based on their cidr prefix or
|
@@ -99,12 +97,12 @@ module Azure::ARM
|
|
99
97
|
|
100
98
|
## return the cidr prefix or netmask of the given subnet ##
|
101
99
|
def subnet_cidr_prefix(subnet)
|
102
|
-
subnet_address_prefix(subnet).split(
|
100
|
+
subnet_address_prefix(subnet).split("/")[1].to_i
|
103
101
|
end
|
104
102
|
|
105
103
|
## method to invoke respective sort methods for the network pools ##
|
106
104
|
def sort_pools(available_networks_pool, used_networks_pool)
|
107
|
-
|
105
|
+
[sort_available_networks(available_networks_pool), sort_used_networks_by_hosts_size(used_networks_pool)]
|
108
106
|
end
|
109
107
|
|
110
108
|
## when a address space in an existing virtual network is not used at all
|
@@ -116,28 +114,28 @@ module Azure::ARM
|
|
116
114
|
|
117
115
|
case network_address.count
|
118
116
|
when 4097..65536
|
119
|
-
prefix =
|
117
|
+
prefix = "20"
|
120
118
|
when 256..4096
|
121
|
-
prefix =
|
119
|
+
prefix = "24"
|
122
120
|
end
|
123
121
|
|
124
122
|
## if the given network is small then do not divide it else divide using
|
125
123
|
## the prefix value calculated above ##
|
126
|
-
prefix.nil? ? address_prefix : network_address.network.address.concat(
|
124
|
+
prefix.nil? ? address_prefix : network_address.network.address.concat("/" + prefix)
|
127
125
|
end
|
128
126
|
|
129
127
|
## check if the available_network is part of the subnet_network or vice-versa ##
|
130
128
|
def in_use_network?(subnet_network, available_network)
|
131
129
|
(subnet_network.include? available_network) ||
|
132
|
-
|
130
|
+
(available_network.include? subnet_network)
|
133
131
|
end
|
134
132
|
|
135
133
|
## calculate and return address_prefix for the new subnet to be added in the
|
136
134
|
## existing virtual network ##
|
137
135
|
def new_subnet_address_prefix(vnet_address_prefix, subnets)
|
138
|
-
if subnets.empty?
|
136
|
+
if subnets.empty? ## no subnets exist in the given address space of the virtual network, so divide the network into smaller subnets (based on the network size) and allocate space for the new subnet to be added ##
|
139
137
|
divide_network(vnet_address_prefix)
|
140
|
-
else
|
138
|
+
else ## subnets exist in vnet, calculate new address_prefix for the new subnet based on the space taken by these existing subnets under the given address space of the virtual network ##
|
141
139
|
vnet_network_address = IPAddress(vnet_address_prefix)
|
142
140
|
subnets = sort_subnets_by_cidr_prefix(subnets)
|
143
141
|
available_networks_pool = Array.new
|
@@ -153,7 +151,7 @@ module Azure::ARM
|
|
153
151
|
## cidr prefix value) into the available_networks_pool ##
|
154
152
|
available_networks_pool.push(
|
155
153
|
vnet_network_address.subnet(subnet_cidr_prefix(subnet))
|
156
|
-
).flatten!.uniq! { |nwrk| [ nwrk.network.address, nwrk.prefix ].join(
|
154
|
+
).flatten!.uniq! { |nwrk| [ nwrk.network.address, nwrk.prefix ].join(":") }
|
157
155
|
|
158
156
|
## add current subnet into the used_networks_pool ##
|
159
157
|
used_networks_pool.push(
|
@@ -167,9 +165,9 @@ module Azure::ARM
|
|
167
165
|
## trim the available_networks_pool based on the networks already
|
168
166
|
## allocated to the existing subnets ##
|
169
167
|
used_networks_pool.each do |subnet_network|
|
170
|
-
available_networks_pool.delete_if
|
171
|
-
|
172
|
-
|
168
|
+
available_networks_pool.delete_if do |available_network|
|
169
|
+
in_use_network?(subnet_network, available_network)
|
170
|
+
end
|
173
171
|
end
|
174
172
|
|
175
173
|
## sort both the network pools after trimming the available_networks_pool ##
|
@@ -180,7 +178,7 @@ module Azure::ARM
|
|
180
178
|
## space available in the vnet_address_prefix network for the new subnet ##
|
181
179
|
if !available_networks_pool.empty? && available_networks_pool.first.network?
|
182
180
|
available_networks_pool.first.network.address.concat("/" + available_networks_pool.first.prefix.to_s)
|
183
|
-
else
|
181
|
+
else ## space not available in the vnet_address_prefix network for the new subnet ##
|
184
182
|
nil
|
185
183
|
end
|
186
184
|
end
|
@@ -200,24 +198,24 @@ module Azure::ARM
|
|
200
198
|
vnet_address_space[vnet_address_prefix_count], subnets
|
201
199
|
)
|
202
200
|
)
|
203
|
-
vnet_address_prefix_count
|
201
|
+
vnet_address_prefix_count += 1
|
204
202
|
end
|
205
203
|
|
206
|
-
if new_subnet_prefix
|
204
|
+
if new_subnet_prefix ## found space for new subnet ##
|
207
205
|
vnet_config[:subnets].push(
|
208
206
|
subnet(subnet_name, new_subnet_prefix)
|
209
207
|
)
|
210
|
-
else
|
208
|
+
else ## no space available in the virtual network for the new subnet ##
|
211
209
|
raise "Unable to add subnet #{subnet_name} into the virtual network #{vnet_config[:virtualNetworkName]}, no address space available !!!"
|
212
210
|
end
|
213
211
|
|
214
212
|
vnet_config
|
215
213
|
end
|
216
214
|
|
217
|
-
## virtual network configuration creation for the new vnet creation or to
|
215
|
+
## virtual network configuration creation for the new vnet creation or to
|
218
216
|
## handle existing vnet ##
|
219
217
|
def create_vnet_config(resource_group_name, vnet_name, vnet_subnet_name)
|
220
|
-
raise ArgumentError,
|
218
|
+
raise ArgumentError, "GatewaySubnet cannot be used as the name for --azure-vnet-subnet-name option. GatewaySubnet can only be used for virtual network gateways." if vnet_subnet_name == "GatewaySubnet"
|
221
219
|
|
222
220
|
vnet_config = {}
|
223
221
|
subnets = nil
|
@@ -225,18 +223,20 @@ module Azure::ARM
|
|
225
223
|
## check whether user passed or default named virtual network exist or not ##
|
226
224
|
vnet = get_vnet(resource_group_name, vnet_name)
|
227
225
|
vnet_config[:virtualNetworkName] = vnet_name
|
228
|
-
if vnet
|
226
|
+
if vnet ## handle resources in the existing virtual network ##
|
229
227
|
vnet_config[:addressPrefixes] = vnet_address_spaces(vnet)
|
230
228
|
vnet_config[:subnets] = Array.new
|
231
229
|
subnets = subnets_list(resource_group_name, vnet_name)
|
232
|
-
subnets
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
230
|
+
if subnets
|
231
|
+
subnets.each do |subnet|
|
232
|
+
flag = false if subnet.name == vnet_subnet_name ## given subnet already exist in the virtual network ##
|
233
|
+
## preserve the existing subnet resources ##
|
234
|
+
vnet_config[:subnets].push(
|
235
|
+
subnet(subnet.name, subnet_address_prefix(subnet))
|
236
|
+
)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
else ## create config for new vnet ##
|
240
240
|
vnet_config[:addressPrefixes] = [ "10.0.0.0/16" ]
|
241
241
|
vnet_config[:subnets] = Array.new
|
242
242
|
vnet_config[:subnets].push(
|
@@ -1,184 +1,181 @@
|
|
1
|
-
#
|
2
|
-
# Author:: Nimisha Sharad (nimisha.sharad@clogeny.com)
|
3
|
-
# Copyright:: Copyright
|
4
|
-
# License:: Apache License, Version 2.0
|
5
|
-
#
|
6
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
-
# you may not use this file except in compliance with the License.
|
8
|
-
# You may obtain a copy of the License at
|
9
|
-
#
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
-
# See the License for the specific language governing permissions and
|
16
|
-
# limitations under the License.
|
17
|
-
#
|
18
|
-
|
19
|
-
# XPLAT stores the access token and other information in windows credential manager.
|
20
|
-
# Using FFI to call CredRead function
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require "chef/win32/api"
|
25
|
-
|
26
|
-
module Azure::ARM
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
#
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
1
|
+
#
|
2
|
+
# Author:: Nimisha Sharad (nimisha.sharad@clogeny.com)
|
3
|
+
# Copyright:: Copyright 2015-2018 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
# XPLAT stores the access token and other information in windows credential manager.
|
20
|
+
# Using FFI to call CredRead function
|
21
|
+
require "chef"
|
22
|
+
require "mixlib/shellout"
|
23
|
+
require "ffi"
|
24
|
+
require "chef/win32/api"
|
25
|
+
|
26
|
+
module Azure::ARM
|
27
|
+
|
28
|
+
module ReadCred
|
29
|
+
|
30
|
+
extend Chef::ReservedNames::Win32::API
|
31
|
+
extend FFI::Library
|
32
|
+
|
33
|
+
ffi_lib "Advapi32"
|
34
|
+
|
35
|
+
CRED_TYPE_GENERIC = 1
|
36
|
+
CRED_TYPE_DOMAIN_PASSWORD = 2
|
37
|
+
CRED_TYPE_DOMAIN_CERTIFICATE = 3
|
38
|
+
CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 4
|
39
|
+
|
40
|
+
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx
|
41
|
+
class FILETIME < FFI::Struct
|
42
|
+
layout :dwLowDateTime, :DWORD,
|
43
|
+
:dwHighDateTime, :DWORD
|
44
|
+
end
|
45
|
+
|
46
|
+
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374790(v=vs.85).aspx
|
47
|
+
class CREDENTIAL_ATTRIBUTE < FFI::Struct
|
48
|
+
layout :Keyword, :LPTSTR,
|
49
|
+
:Flags, :DWORD,
|
50
|
+
:ValueSize, :DWORD,
|
51
|
+
:Value, :LPBYTE
|
52
|
+
end
|
53
|
+
|
54
|
+
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx
|
55
|
+
class CREDENTIAL_OBJECT < FFI::Struct
|
56
|
+
layout :Flags, :DWORD,
|
57
|
+
:Type, :DWORD,
|
58
|
+
:TargetName, :LPTSTR,
|
59
|
+
:Comment, :LPTSTR,
|
60
|
+
:LastWritten, FILETIME,
|
61
|
+
:CredentialBlobSize, :DWORD,
|
62
|
+
:CredentialBlob, :LPBYTE,
|
63
|
+
:Persist, :DWORD,
|
64
|
+
:AttributeCount, :DWORD,
|
65
|
+
:Attributes, CREDENTIAL_ATTRIBUTE,
|
66
|
+
:TargetAlias, :LPTSTR,
|
67
|
+
:UserName, :LPTSTR
|
68
|
+
end
|
69
|
+
|
70
|
+
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374804(v=vs.85).aspx
|
71
|
+
safe_attach_function :CredReadW, [:LPCTSTR, :DWORD, :DWORD, :pointer], :BOOL
|
72
|
+
end
|
73
|
+
|
74
|
+
module WindowsCredentials
|
75
|
+
|
76
|
+
include Chef::Mixin::WideString
|
77
|
+
include ReadCred
|
78
|
+
|
79
|
+
def token_details_from_WCM
|
80
|
+
target = target_name
|
81
|
+
|
82
|
+
if target && !target.empty?
|
83
|
+
target_pointer = wstring(target)
|
84
|
+
info_ptr = FFI::MemoryPointer.new(:pointer)
|
85
|
+
cred = CREDENTIAL_OBJECT.new info_ptr
|
86
|
+
cred_result = CredReadW(target_pointer, CRED_TYPE_GENERIC, 0, cred)
|
87
|
+
translated_cred = CREDENTIAL_OBJECT.new(info_ptr.read_pointer)
|
88
|
+
|
89
|
+
target_obj = translated_cred[:TargetName].read_wstring.split("::") if translated_cred[:TargetName].read_wstring
|
90
|
+
cred_blob = translated_cred[:CredentialBlob].get_bytes(0, translated_cred[:CredentialBlobSize]).split("::")
|
91
|
+
|
92
|
+
tokentype = target_obj.select { |obj| obj.include? "tokenType" }
|
93
|
+
user = target_obj.select { |obj| obj.include? "userId" }
|
94
|
+
clientid = target_obj.select { |obj| obj.include? "clientId" }
|
95
|
+
expiry_time = target_obj.select { |obj| obj.include? "expiresOn" }
|
96
|
+
access_token = cred_blob.select { |obj| obj.include? "a:" }
|
97
|
+
refresh_token = cred_blob.select { |obj| obj.include? "r:" }
|
98
|
+
|
99
|
+
credential = {}
|
100
|
+
credential[:tokentype] = tokentype[0].split(":")[1]
|
101
|
+
credential[:user] = user[0].split(":")[1]
|
102
|
+
credential[:token] = access_token[0].split(":")[1]
|
103
|
+
#Todo: refresh_token is not complete currently
|
104
|
+
# target_name method needs to be modified for that
|
105
|
+
credential[:refresh_token] = refresh_token[0].split(":")[1]
|
106
|
+
credential[:clientid] = clientid[0].split(":")[1]
|
107
|
+
credential[:expiry_time] = expiry_time[0].split("expiresOn:")[1].delete("\\")
|
108
|
+
|
109
|
+
# Free memory pointed by info_ptr
|
110
|
+
info_ptr.free
|
111
|
+
else
|
112
|
+
raise "TargetName Not Found"
|
113
|
+
end
|
114
|
+
credential
|
115
|
+
rescue => error
|
116
|
+
ui.error("#{error.message}")
|
117
|
+
Chef::Log.debug("#{error.backtrace.join("\n")}")
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
|
121
|
+
#Todo: For getting the complete refreshToken, both credentials (ending with --0-2 and --1-2) have to be read
|
122
|
+
def target_name
|
123
|
+
# cmdkey command is used for accessing windows credential manager.
|
124
|
+
# Multiple credentials get created in windows credential manager for a single Azure account in xplat-cli
|
125
|
+
# One of them is for common tanent id, which can't be used
|
126
|
+
# Others end with --0-x,--1-x,--2-x etc, where x represents the total no. of credentails across which the token is divided
|
127
|
+
# The one ending with --0-x has the complete accessToken in the credentialBlob.
|
128
|
+
# Refresh Token is split across both credentials (ending with --0-x and --1-x).
|
129
|
+
# Xplat splits the credentials based on the number of bytes of the tokens.
|
130
|
+
# Hence the access token is always found in the one which start with --0-
|
131
|
+
# So selecting the credential on the basis of --0-
|
132
|
+
xplat_creds_cmd = Mixlib::ShellOut.new('cmdkey /list | findstr AzureXplatCli | findstr \--0- | findstr -v common')
|
133
|
+
result = xplat_creds_cmd.run_command
|
134
|
+
target_names = []
|
135
|
+
|
136
|
+
if result.stdout.empty?
|
137
|
+
Chef::Log.debug("Unable to find a credential with --0- and falling back to looking for any credential.")
|
138
|
+
xplat_creds_cmd = Mixlib::ShellOut.new("cmdkey /list | findstr AzureXplatCli | findstr -v common")
|
139
|
+
result = xplat_creds_cmd.run_command
|
140
|
+
|
141
|
+
if result.stdout.empty?
|
142
|
+
raise "Azure Credentials not found. Please run xplat's 'azure login' command"
|
143
|
+
else
|
144
|
+
target_names = result.stdout.split("\n")
|
145
|
+
end
|
146
|
+
else
|
147
|
+
target_names = result.stdout.split("\n")
|
148
|
+
end
|
149
|
+
|
150
|
+
# If "azure login" is run for multiple users, there will be multiple credentials
|
151
|
+
# Picking up the latest logged in user's credentials
|
152
|
+
latest_target = latest_credential_target target_names
|
153
|
+
latest_target
|
154
|
+
end
|
155
|
+
|
156
|
+
def latest_credential_target(targets)
|
157
|
+
case targets.size
|
158
|
+
when 0
|
159
|
+
raise "No Target was found for windows credentials"
|
160
|
+
when 1
|
161
|
+
targets.first.gsub("Target:", "").strip
|
162
|
+
else
|
163
|
+
latest_target = ""
|
164
|
+
max_expiry_time = Time.new(0)
|
165
|
+
|
166
|
+
# Using expiry_time to determine the latest credential
|
167
|
+
targets.each do |target|
|
168
|
+
target_obj = target.split("::")
|
169
|
+
expiry_time_obj = target_obj.select { |obj| obj.include? "expiresOn" }
|
170
|
+
expiry_time = expiry_time_obj[0].split("expiresOn:")[1].delete("\\")
|
171
|
+
if Time.parse(expiry_time) > max_expiry_time
|
172
|
+
latest_target = target
|
173
|
+
max_expiry_time = Time.parse(expiry_time)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
latest_target.gsub("Target:", "").strip
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|