knife-vcloud 0.2.3 → 1.0.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 +7 -0
- data/CHANGELOG.md +44 -1
- data/README.md +356 -91
- data/lib/chef/knife/{vc_catalog_item_show.rb → catalog/vc_catalog_item_show.rb} +13 -13
- data/lib/chef/knife/{vc_catalog_show.rb → catalog/vc_catalog_show.rb} +9 -12
- data/lib/chef/knife/common/vc_bootstrap_common.rb +208 -0
- data/lib/chef/knife/common/vc_catalog_common.rb +58 -0
- data/lib/chef/knife/common/vc_common.rb +165 -0
- data/lib/chef/knife/common/vc_network_common.rb +34 -0
- data/lib/chef/knife/common/vc_vapp_common.rb +49 -0
- data/lib/chef/knife/common/vc_vdc_common.rb +43 -0
- data/lib/chef/knife/common/vc_vm_common.rb +80 -0
- data/lib/chef/knife/network/vc_network_show.rb +45 -0
- data/lib/chef/knife/{vc_org_list.rb → org/vc_org_list.rb} +3 -5
- data/lib/chef/knife/{vc_org_show.rb → org/vc_org_show.rb} +10 -11
- data/lib/chef/knife/ovf/vc_ovf_upload.rb +71 -0
- data/lib/chef/knife/vapp/vc_vapp_bootstrap.rb +51 -0
- data/lib/chef/knife/vapp/vc_vapp_clone.rb +80 -0
- data/lib/chef/knife/{vc_vapp_create.rb → vapp/vc_vapp_create.rb} +10 -9
- data/lib/chef/knife/{vc_vapp_delete.rb → vapp/vc_vapp_delete.rb} +12 -10
- data/lib/chef/knife/vapp/vc_vapp_network_external.rb +101 -0
- data/lib/chef/knife/vapp/vc_vapp_network_internal.rb +151 -0
- data/lib/chef/knife/vapp/vc_vapp_reboot.rb +45 -0
- data/lib/chef/knife/vapp/vc_vapp_reset.rb +44 -0
- data/lib/chef/knife/vapp/vc_vapp_show.rb +90 -0
- data/lib/chef/knife/vapp/vc_vapp_snapshot.rb +58 -0
- data/lib/chef/knife/{vc_vapp_start.rb → vapp/vc_vapp_start.rb} +7 -7
- data/lib/chef/knife/{vc_vapp_stop.rb → vapp/vc_vapp_stop.rb} +7 -7
- data/lib/chef/knife/vapp/vc_vapp_suspend.rb +44 -0
- data/lib/chef/knife/vc_commands.rb +70 -0
- data/lib/chef/knife/vc_login.rb +2 -2
- data/lib/chef/knife/{vc_vdc_show.rb → vdc/vc_vdc_show.rb} +13 -14
- data/lib/chef/knife/vm/vc_vm_bootstrap.rb +48 -0
- data/lib/chef/knife/vm/vc_vm_config_guest.rb +110 -0
- data/lib/chef/knife/{vc_vm_config_network.rb → vm/vc_vm_config_network.rb} +17 -11
- data/lib/chef/knife/vm/vc_vm_reboot.rb +44 -0
- data/lib/chef/knife/vm/vc_vm_reset.rb +44 -0
- data/lib/chef/knife/vm/vc_vm_set_disks.rb +78 -0
- data/lib/chef/knife/vm/vc_vm_set_info.rb +79 -0
- data/lib/chef/knife/{vc_vm_show.rb → vm/vc_vm_show.rb} +35 -18
- data/lib/chef/knife/vm/vc_vm_start.rb +44 -0
- data/lib/chef/knife/vm/vc_vm_stop.rb +44 -0
- data/lib/chef/knife/vm/vc_vm_suspend.rb +44 -0
- data/lib/knife-vcloud/version.rb +3 -0
- metadata +69 -38
- data/lib/chef/knife/vc_common.rb +0 -103
- data/lib/chef/knife/vc_vapp_config_network.rb +0 -63
- data/lib/chef/knife/vc_vapp_show.rb +0 -59
- data/lib/chef/knife/vc_vm_config_guest.rb +0 -67
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Stefano Tortarolo (<stefano.tortarolo@gmail.com>)
|
3
|
-
# Copyright:: Copyright (c) 2012
|
3
|
+
# Copyright:: Copyright (c) 2012-2013
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -16,39 +16,39 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require 'chef/knife/vc_common'
|
20
|
-
|
21
19
|
class Chef
|
22
20
|
class Knife
|
23
21
|
class VcCatalogItemShow < Chef::Knife
|
24
22
|
include Knife::VcCommon
|
23
|
+
include Knife::VcCatalogCommon
|
25
24
|
|
26
|
-
banner "knife vc catalog item show [
|
25
|
+
banner "knife vc catalog item show [CATALOG_ITEM] (options)"
|
27
26
|
|
28
27
|
def run
|
29
28
|
$stdout.sync = true
|
30
29
|
|
31
|
-
|
30
|
+
item_arg = @name_args.first
|
32
31
|
|
33
32
|
connection.login
|
33
|
+
catalog_item = get_catalog_item(item_arg)
|
34
|
+
connection.logout
|
34
35
|
|
35
36
|
header = [
|
36
37
|
ui.color('Name', :bold),
|
37
38
|
ui.color('Template ID', :bold)
|
38
39
|
]
|
39
40
|
|
40
|
-
|
41
|
-
connection.logout
|
42
|
-
|
43
|
-
puts "#{ui.color('Description:', :cyan)} #{description}"
|
41
|
+
ui.msg "#{ui.color('Description:', :cyan)} #{catalog_item[:description]}"
|
44
42
|
list = header
|
45
43
|
list.flatten!
|
46
|
-
|
47
|
-
|
48
|
-
list << (
|
44
|
+
|
45
|
+
catalog_item[:items].each do |item|
|
46
|
+
list << (item[:name] || '')
|
47
|
+
list << (item[:id] || '')
|
48
|
+
# TODO: show VMs using this item? item[:vms_hash]
|
49
49
|
end
|
50
50
|
|
51
|
-
|
51
|
+
ui.msg ui.list(list, :columns_across, 2)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Stefano Tortarolo (<stefano.tortarolo@gmail.com>)
|
3
|
-
# Copyright:: Copyright (c) 2012
|
3
|
+
# Copyright:: Copyright (c) 2012-2013
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -16,39 +16,36 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require 'chef/knife/vc_common'
|
20
|
-
|
21
19
|
class Chef
|
22
20
|
class Knife
|
23
21
|
class VcCatalogShow < Chef::Knife
|
24
22
|
include Knife::VcCommon
|
23
|
+
include Knife::VcCatalogCommon
|
25
24
|
|
26
|
-
banner "knife vc catalog show [
|
25
|
+
banner "knife vc catalog show [CATALOG] (options)"
|
27
26
|
|
28
27
|
def run
|
29
28
|
$stdout.sync = true
|
30
29
|
|
31
|
-
|
32
|
-
|
30
|
+
catalog_arg = @name_args.shift
|
33
31
|
connection.login
|
32
|
+
catalog = get_catalog(catalog_arg)
|
33
|
+
connection.logout
|
34
34
|
|
35
35
|
header = [
|
36
36
|
ui.color('Name', :bold),
|
37
37
|
ui.color('ID', :bold)
|
38
38
|
]
|
39
39
|
|
40
|
-
|
41
|
-
connection.logout
|
42
|
-
|
43
|
-
puts "#{ui.color('Description:', :cyan)} #{description}"
|
40
|
+
ui.msg "#{ui.color('Description:', :cyan)} #{catalog[:description]}"
|
44
41
|
list = header
|
45
42
|
list.flatten!
|
46
|
-
items.each do |k, v|
|
43
|
+
sort_by_key(catalog[:items]).each do |k, v|
|
47
44
|
list << (k || '')
|
48
45
|
list << (v || '')
|
49
46
|
end
|
50
47
|
|
51
|
-
|
48
|
+
ui.msg ui.list(list, :columns_across, 2)
|
52
49
|
end
|
53
50
|
end
|
54
51
|
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Stefano Tortarolo (<stefano.tortarolo@gmail.com>)
|
3
|
+
# Copyright:: Copyright (c) 2013
|
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
|
+
class Chef
|
20
|
+
class Knife
|
21
|
+
module VcBootstrapCommon
|
22
|
+
def self.included(includer)
|
23
|
+
includer.class_eval do
|
24
|
+
deps do
|
25
|
+
require 'chef/knife/bootstrap'
|
26
|
+
require 'chef/knife/bootstrap_windows_winrm'
|
27
|
+
require 'chef/knife/core/windows_bootstrap_context'
|
28
|
+
Chef::Knife::Bootstrap.load_deps
|
29
|
+
end
|
30
|
+
|
31
|
+
option :run_list,
|
32
|
+
:short => "-r RUN_LIST",
|
33
|
+
:long => "--run-list RUN_LIST",
|
34
|
+
:description => "Comma separated list of roles/recipes to apply",
|
35
|
+
:proc => lambda { |o| o.split(/[\s,]+/) },
|
36
|
+
:default => []
|
37
|
+
|
38
|
+
option :distro,
|
39
|
+
:short => "-d DISTRO",
|
40
|
+
:long => "--distro DISTRO",
|
41
|
+
:description => "Bootstrap a distro using a template; default is 'chef-full'",
|
42
|
+
:proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
|
43
|
+
:default => "chef-full"
|
44
|
+
|
45
|
+
option :bootstrap_windows,
|
46
|
+
:long => "--[no-]bootstrap-windows",
|
47
|
+
:description => "The machine to be bootstrapped is Windows",
|
48
|
+
:boolean => true,
|
49
|
+
:default => false
|
50
|
+
|
51
|
+
option :bootstrap_proxy,
|
52
|
+
:long => "--bootstrap-proxy PROXY_URL",
|
53
|
+
:description => "The proxy server for the node being bootstrapped",
|
54
|
+
:proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_proxy] = v }
|
55
|
+
|
56
|
+
option :ssh_user,
|
57
|
+
:short => "-x USERNAME",
|
58
|
+
:long => "--ssh-user USERNAME",
|
59
|
+
:description => "The ssh username",
|
60
|
+
:default => "root"
|
61
|
+
|
62
|
+
option :ssh_password,
|
63
|
+
:short => "-P PASSWORD",
|
64
|
+
:long => "--ssh-password PASSWORD",
|
65
|
+
:description => "The ssh password"
|
66
|
+
|
67
|
+
option :ssh_port,
|
68
|
+
:short => "-p PORT",
|
69
|
+
:long => "--ssh-port PORT",
|
70
|
+
:description => "The ssh port",
|
71
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key },
|
72
|
+
:default => 22
|
73
|
+
|
74
|
+
option :ssh_gateway,
|
75
|
+
:short => "-G GATEWAY",
|
76
|
+
:long => "--ssh-gateway GATEWAY",
|
77
|
+
:description => "The ssh gateway",
|
78
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
|
79
|
+
|
80
|
+
option :forward_agent,
|
81
|
+
:short => "-A",
|
82
|
+
:long => "--forward-agent",
|
83
|
+
:description => "Enable SSH agent forwarding",
|
84
|
+
:boolean => true
|
85
|
+
|
86
|
+
option :identity_file,
|
87
|
+
:short => "-i IDENTITY_FILE",
|
88
|
+
:long => "--identity-file IDENTITY_FILE",
|
89
|
+
:description => "The SSH identity file used for authentication"
|
90
|
+
|
91
|
+
option :host_key_verify,
|
92
|
+
:long => "--[no-]host-key-verify",
|
93
|
+
:description => "Verify host key, enabled by default.",
|
94
|
+
:boolean => true,
|
95
|
+
:default => true
|
96
|
+
|
97
|
+
option :max_tries,
|
98
|
+
:long => "--max-tries MAX_TRIES",
|
99
|
+
:description => "Max number of connection tries for each VM",
|
100
|
+
:default => 5
|
101
|
+
|
102
|
+
option :secret,
|
103
|
+
:short => "-s SECRET",
|
104
|
+
:long => "--secret ",
|
105
|
+
:description => "The secret key to use to encrypt data bag item values",
|
106
|
+
:proc => Proc.new { |s| Chef::Config[:knife][:secret] = s }
|
107
|
+
|
108
|
+
option :secret_file,
|
109
|
+
:long => "--secret-file SECRET_FILE",
|
110
|
+
:description => "A file containing the secret key to use to encrypt data bag item values",
|
111
|
+
:proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf }
|
112
|
+
|
113
|
+
option :template_file,
|
114
|
+
:long => "--template-file TEMPLATE_FILE",
|
115
|
+
:description => "Template file to use for bootstrap",
|
116
|
+
:proc => Proc.new { |sf| Chef::Config[:knife][:template_file] = tf }
|
117
|
+
|
118
|
+
Chef::Config[:knife][:hints] ||= {"vcloud" => {}}
|
119
|
+
option :hint,
|
120
|
+
:long => "--hint HINT_FILE",
|
121
|
+
:description => "Specify Ohai Hint to be set on the bootstrap target.",
|
122
|
+
:proc => Proc.new { |path| Chef::Config[:knife][:hints]["vcloud"] = path ? JSON.parse(::File.read(path)) : Hash.new }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def bootstrap_vm(vm_name, id, addresses)
|
127
|
+
ui.msg "Bootstrap VM: #{vm_name}..."
|
128
|
+
|
129
|
+
max_tries = locate_config_value(:max_tries)
|
130
|
+
ssh_port = locate_config_value(:ssh_port)
|
131
|
+
|
132
|
+
# Stop at the first reachable IP address
|
133
|
+
reachable_ip = nil
|
134
|
+
addresses.each do |address|
|
135
|
+
tries = 1
|
136
|
+
|
137
|
+
until tries > max_tries
|
138
|
+
ui.info "Trying to reach #{address} (try #{tries}/#{max_tries})"
|
139
|
+
|
140
|
+
if test_connection_ssh(address, ssh_port)
|
141
|
+
reachable_ip = address
|
142
|
+
break
|
143
|
+
end
|
144
|
+
tries += 1
|
145
|
+
end
|
146
|
+
break if reachable_ip
|
147
|
+
end
|
148
|
+
|
149
|
+
if reachable_ip
|
150
|
+
ui.msg "Bootstrap IP: #{reachable_ip}"
|
151
|
+
bootstrap_for_node(reachable_ip).run
|
152
|
+
else
|
153
|
+
ui.warn "No reachable IPs. Not bootstrapping."
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
def test_connection_ssh(hostname, port)
|
159
|
+
socket = TCPSocket.new(hostname, port)
|
160
|
+
|
161
|
+
result = IO.select([socket], nil, nil, @test_connection_timeout)
|
162
|
+
if result
|
163
|
+
ui.info("\t#{hostname}:#{port} replied with: #{socket.gets}")
|
164
|
+
true
|
165
|
+
else
|
166
|
+
false
|
167
|
+
end
|
168
|
+
rescue Errno::ETIMEDOUT, Errno::EPERM => e
|
169
|
+
ui.info("\tUnable to reach #{hostname}:#{port} => #{e.message}")
|
170
|
+
false
|
171
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ECONNRESET => e
|
172
|
+
ui.info("\tUnable to reach #{hostname}:#{port} => #{e.message}")
|
173
|
+
sleep 2
|
174
|
+
false
|
175
|
+
ensure
|
176
|
+
socket && socket.close
|
177
|
+
end
|
178
|
+
|
179
|
+
def bootstrap_for_node(fqdn)
|
180
|
+
bootstrap = Chef::Knife::Bootstrap.new
|
181
|
+
bootstrap.name_args = [fqdn]
|
182
|
+
bootstrap.config[:ssh_user] = locate_config_value(:ssh_user) || "root"
|
183
|
+
bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
|
184
|
+
bootstrap.config[:use_sudo] = true unless locate_config_value(:ssh_user) == 'root'
|
185
|
+
bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
|
186
|
+
bootstrap.config[:ssh_password] = config[:ssh_password]
|
187
|
+
bootstrap.config[:ssh_port] = locate_config_value(:ssh_port)
|
188
|
+
bootstrap.config[:ssh_gateway] = locate_config_value(:ssh_gateway)
|
189
|
+
bootstrap.config[:forward_agent] = locate_config_value(:forward_agent)
|
190
|
+
bootstrap.config[:identity_file] = locate_config_value(:identity_file)
|
191
|
+
bootstrap.config[:manual] = true
|
192
|
+
bootstrap.config[:host_key_verify] = locate_config_value(:host_key_verify)
|
193
|
+
|
194
|
+
bootstrap.config[:run_list] = config[:run_list]
|
195
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
196
|
+
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
197
|
+
bootstrap.config[:distro] = locate_config_value(:distro)
|
198
|
+
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
199
|
+
bootstrap.config[:bootstrap_proxy] = locate_config_value(:bootstrap_proxy)
|
200
|
+
bootstrap.config[:environment] = config[:environment]
|
201
|
+
bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:secret)
|
202
|
+
bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:secret_file)
|
203
|
+
|
204
|
+
bootstrap
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Stefano Tortarolo (<stefano.tortarolo@gmail.com>)
|
3
|
+
# Copyright:: Copyright (c) 2013
|
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
|
+
class Chef
|
20
|
+
class Knife
|
21
|
+
module VcCatalogCommon
|
22
|
+
def self.included(includer)
|
23
|
+
includer.class_eval do
|
24
|
+
option :vcloud_catalog,
|
25
|
+
:long => "--catalog CATALOG_NAME",
|
26
|
+
:description => "Catalog to whom Catalog Item belongs",
|
27
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:vcloud_catalog] = key }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_catalog(catalog_arg)
|
32
|
+
catalog = nil
|
33
|
+
org_name = locate_org_option
|
34
|
+
|
35
|
+
org = connection.get_organization_by_name org_name
|
36
|
+
catalog = connection.get_catalog_by_name org, catalog_arg
|
37
|
+
|
38
|
+
raise ArgumentError, "Catalog #{catalog_arg} not found" unless catalog
|
39
|
+
catalog
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_catalog_item(catalog_item_arg)
|
43
|
+
item = nil
|
44
|
+
catalog_name = locate_config_value(:vcloud_catalog)
|
45
|
+
|
46
|
+
unless catalog_name
|
47
|
+
notice_msg("--catalog not specified, assuming CATALOG_ITEM is an ID")
|
48
|
+
item = connection.get_catalog_item catalog_item_arg
|
49
|
+
else
|
50
|
+
catalog = get_catalog(catalog_name)
|
51
|
+
item = connection.get_catalog_item_by_name catalog[:id], catalog_item_arg
|
52
|
+
end
|
53
|
+
raise ArgumentError, "Catalog Item #{catalog_item_arg} not found" unless item
|
54
|
+
item
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Stefano Tortarolo (<stefano.tortarolo@gmail.com>)
|
3
|
+
# Copyright:: Copyright (c) 2012-2013
|
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
|
+
require 'chef/knife'
|
20
|
+
require 'date'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Knife
|
24
|
+
module VcCommon
|
25
|
+
def self.included(includer)
|
26
|
+
includer.class_eval do
|
27
|
+
|
28
|
+
deps do
|
29
|
+
require 'vcloud-rest/connection'
|
30
|
+
require 'chef/api_client'
|
31
|
+
end
|
32
|
+
|
33
|
+
option :vcloud_url,
|
34
|
+
:short => "-H URL",
|
35
|
+
:long => "--url URL",
|
36
|
+
:description => "The vCloud endpoint URL",
|
37
|
+
:proc => Proc.new { |url| Chef::Config[:knife][:vcloud_url] = url }
|
38
|
+
|
39
|
+
option :vcloud_user_login,
|
40
|
+
:short => "-U USER",
|
41
|
+
:long => "--user-login USER",
|
42
|
+
:description => "Your vCloud User",
|
43
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:vcloud_user_login] = key }
|
44
|
+
|
45
|
+
option :vcloud_password_login,
|
46
|
+
:short => "-P SECRET",
|
47
|
+
:long => "--password-login SECRET",
|
48
|
+
:description => "Your vCloud secret key",
|
49
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:vcloud_password_login] = key }
|
50
|
+
|
51
|
+
option :vcloud_org_login,
|
52
|
+
:long => "--org-login ORGANIZATION",
|
53
|
+
:description => "Your vCloud Organization",
|
54
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:vcloud_org_login] = key }
|
55
|
+
|
56
|
+
option :vcloud_api_version,
|
57
|
+
:short => "-A API_VERSION",
|
58
|
+
:long => "--api-version API_VERSION",
|
59
|
+
:description => "vCloud API version (1.5 and 5.1 supported)",
|
60
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:vcloud_api_version] = key }
|
61
|
+
|
62
|
+
option :vcloud_system_admin,
|
63
|
+
:long => "--[no-]system-admin",
|
64
|
+
:description => "Set to true if user is a vCloud System Administrator",
|
65
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:vcloud_system_admin] = key },
|
66
|
+
:boolean => true,
|
67
|
+
:default => false
|
68
|
+
|
69
|
+
option :vcloud_org,
|
70
|
+
:long => "--org ORG_NAME",
|
71
|
+
:description => "Organization to use (only for System Administrators)",
|
72
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:vcloud_org] = key }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def connection
|
77
|
+
unless @connection
|
78
|
+
@connection = VCloudClient::Connection.new(
|
79
|
+
locate_config_value(:vcloud_url),
|
80
|
+
locate_config_value(:vcloud_user_login),
|
81
|
+
locate_config_value(:vcloud_password_login),
|
82
|
+
locate_config_value(:vcloud_org_login),
|
83
|
+
locate_config_value(:vcloud_api_version)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
@connection
|
88
|
+
end
|
89
|
+
|
90
|
+
# Locate the correct organization option
|
91
|
+
#
|
92
|
+
# System Administrators can browse several organizations and thus --org
|
93
|
+
# can be used to specify different organizations
|
94
|
+
#
|
95
|
+
# Only --org-login is valid for other users
|
96
|
+
def locate_org_option
|
97
|
+
org = locate_config_value(:vcloud_org_login)
|
98
|
+
|
99
|
+
if locate_config_value(:vcloud_system_admin)
|
100
|
+
return locate_config_value(:vcloud_org) || org
|
101
|
+
end
|
102
|
+
|
103
|
+
if locate_config_value(:vcloud_org)
|
104
|
+
ui.warn("--org option is available only for vCloud System Administrators. " \
|
105
|
+
"Using --org-login ('#{org}').")
|
106
|
+
end
|
107
|
+
return org
|
108
|
+
end
|
109
|
+
|
110
|
+
def out_msg(label, value)
|
111
|
+
if value && !value.empty?
|
112
|
+
ui.msg("#{ui.color(label, :cyan)}: #{value}")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def notice_msg(value)
|
117
|
+
if value && !value.empty?
|
118
|
+
ui.info("#{ui.color('Note:', :bold)} #{value}")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def locate_config_value(key)
|
123
|
+
key = key.to_sym
|
124
|
+
Chef::Config[:knife][key] || config[key]
|
125
|
+
end
|
126
|
+
|
127
|
+
def wait_task(connection, task_id)
|
128
|
+
result = connection.wait_task_completion task_id
|
129
|
+
|
130
|
+
elapsed = humanize_elapsed_time(result[:start_time], result[:end_time])
|
131
|
+
|
132
|
+
out_msg("Summary",
|
133
|
+
"Status: #{ui.color(result[:status], :cyan)} - time elapsed: #{elapsed}")
|
134
|
+
|
135
|
+
if result[:errormsg]
|
136
|
+
ui.warn(ui.color("ATTENTION: #{result[:errormsg]}", :red))
|
137
|
+
end
|
138
|
+
|
139
|
+
result[:errormsg].nil?
|
140
|
+
end
|
141
|
+
|
142
|
+
def pretty_symbol(key)
|
143
|
+
key.to_s.gsub('_', ' ').capitalize
|
144
|
+
end
|
145
|
+
|
146
|
+
def sort_by_key(collection)
|
147
|
+
collection.sort_by {|k, v| k }
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
def humanize_elapsed_time(start_time, end_time)
|
152
|
+
start_time = Time.parse(start_time || Time.now)
|
153
|
+
end_time = Time.parse(end_time || Time.now)
|
154
|
+
secs = (end_time - start_time)
|
155
|
+
|
156
|
+
[[60, :seconds],
|
157
|
+
[60, :minutes],
|
158
|
+
[24, :hours]].map do |count, name|
|
159
|
+
secs, n = secs.divmod(count)
|
160
|
+
"#{n} #{name}" unless n <= 0
|
161
|
+
end.compact.reverse.join(' ')
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|