knife-vcloud 0.2.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|