knife-cloudstack-fog 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,57 +1,57 @@
1
- # Author:: Takashi Kanai (<anikundesu@gmail.com>)
2
- # Copyright:: Copyright (c) 2012 IDC Frontier Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
-
19
- require 'chef/knife/cloudstack_base'
20
-
21
- class Chef
22
- class Knife
23
- class CloudstackPublicipList < Knife
24
-
25
- include Knife::CloudstackBase
26
-
27
- banner "knife cloudstack publicip list"
28
-
29
- def run
30
- $stdout.sync = true
31
-
32
- validate!
33
-
34
- publicip_list = [
35
- ui.color('ID', :bold),
36
- ui.color('ipaddress', :bold),
37
- ui.color('isSourceNAT', :bold),
38
- ui.color('isStaticNAT', :bold),
39
- ui.color('VirtualMachineDisplayName', :bold)
40
- ]
41
- response = connection.list_public_ip_addresses['listpublicipaddressesresponse']
42
- if publicips = response['publicipaddress']
43
- publicips.each do |publicip|
44
- publicip_list << publicip['id'].to_s
45
- publicip_list << publicip['ipaddress'].to_s
46
- publicip_list << publicip['issourcenat'].to_s
47
- publicip_list << publicip['isstaticnat'].to_s
48
- publicip_list << publicip['virtualmachinedisplayname'].to_s
49
- end
50
- end
51
- puts ui.list(publicip_list, :columns_across, 5)
52
-
53
- end
54
-
55
- end
56
- end
57
- end
1
+ # Author:: Takashi Kanai (<anikundesu@gmail.com>)
2
+ # Copyright:: Copyright (c) 2012 IDC Frontier Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+
19
+ require 'chef/knife/cloudstack_base'
20
+
21
+ class Chef
22
+ class Knife
23
+ class CloudstackPublicipList < Knife
24
+
25
+ include Knife::CloudstackBase
26
+
27
+ banner "knife cloudstack publicip list"
28
+
29
+ def run
30
+ $stdout.sync = true
31
+
32
+ validate!
33
+
34
+ publicip_list = [
35
+ ui.color('ID', :bold),
36
+ ui.color('ipaddress', :bold),
37
+ ui.color('isSourceNAT', :bold),
38
+ ui.color('isStaticNAT', :bold),
39
+ ui.color('VirtualMachineDisplayName', :bold)
40
+ ]
41
+ response = connection.list_public_ip_addresses['listpublicipaddressesresponse']
42
+ if publicips = response['publicipaddress']
43
+ publicips.each do |publicip|
44
+ publicip_list << publicip['id'].to_s
45
+ publicip_list << publicip['ipaddress'].to_s
46
+ publicip_list << publicip['issourcenat'].to_s
47
+ publicip_list << publicip['isstaticnat'].to_s
48
+ publicip_list << publicip['virtualmachinedisplayname'].to_s
49
+ end
50
+ end
51
+ puts ui.list(publicip_list, :columns_across, 5)
52
+
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -1,124 +1,124 @@
1
- # Author:: Jeff Moody (<jmoody@datapipe.com>)
2
- # Copyright:: Copyright (c) 2012 Datapipe
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
-
19
- require 'chef/knife/cloudstack_base'
20
-
21
- class Chef
22
- class Knife
23
- class CloudstackSecuritygroupList < Knife
24
-
25
- include Knife::CloudstackBase
26
-
27
- banner "knife cloudstack securitygroup list (options)"
28
- option :groupid,
29
- :short => "-g GROUPID",
30
- :long => "--groupid GROUPID",
31
- :description => "List the rules contained within a Security Group, specified by ID",
32
- :default => 'none'
33
- option :groupname,
34
- :short => "-G GROUPNAME",
35
- :long => "--groupname GROUPNAME",
36
- :description => "List the rules contained within a Security Group, specified by name.",
37
- :default => 'none'
38
-
39
- def sg_details_list(securitygroup_list, securitygroup_details, groups, options={})
40
- temp = groups
41
- if groupid = options[:groupid]
42
- temp.reject!{|g| g['id'] != groupid.to_i}
43
- end
44
- if groupname = options[:groupname]
45
- temp.reject!{|g| g['name'] != groupname}
46
- end
47
-
48
- temp.each do |securitygroup|
49
- securitygroup_list << securitygroup['id'].to_s
50
- securitygroup_list << securitygroup['name'].to_s
51
- securitygroup_list << securitygroup['description'].to_s
52
- if securitygroup['ingressrule'].nil?
53
- securitygroup_details << ' '
54
- else
55
- securitygroup['ingressrule'].each do |ingressrule|
56
- rule_details = []
57
- securitygroup_details << ingressrule['protocol'].to_s
58
- securitygroup_details << ingressrule['startport'].to_s
59
- securitygroup_details << ingressrule['endport'].to_s
60
- if ingressrule['cidr'].nil?
61
- rule_details << ingressrule['securitygroupname'].to_s
62
- rule_details << ingressrule['account'].to_s
63
- else
64
- rule_details << ingressrule['cidr'].to_s
65
- end
66
- securitygroup_details << rule_details.join(", ")
67
- end
68
- end
69
- end
70
- end
71
-
72
- def run
73
- $stdout.sync = true
74
-
75
- validate!
76
- groupid = locate_config_value(:groupid)
77
- groupname = locate_config_value(:groupname)
78
-
79
- if (groupid == 'none' and groupname == 'none')
80
- securitygroup_list = [
81
- ui.color('ID', :bold),
82
- ui.color('Name', :bold),
83
- ui.color('Description', :bold)
84
- ]
85
- response = connection.list_security_groups['listsecuritygroupsresponse']
86
- if securitygroups = response['securitygroup']
87
- securitygroups.each do |securitygroup|
88
- securitygroup_list << securitygroup['id'].to_s
89
- securitygroup_list << securitygroup['name'].to_s
90
- securitygroup_list << securitygroup['description'].to_s
91
- end
92
- end
93
- puts ui.list(securitygroup_list, :columns_across, 3)
94
- else
95
- securitygroup_details = [
96
- ui.color('Protocol', :bold),
97
- ui.color('Start Port', :bold),
98
- ui.color('End Port', :bold),
99
- ui.color('Restricted To', :bold)
100
- ]
101
- securitygroup_list = [
102
- ui.color('ID', :bold),
103
- ui.color('Name', :bold),
104
- ui.color('Description', :bold)
105
- ]
106
-
107
- if response = connection.list_security_groups['listsecuritygroupsresponse']
108
- if securitygroups = response['securitygroup']
109
- filters = {}
110
- filters[:groupid] = groupid unless groupid == 'none'
111
- filters[:groupname] = groupname unless groupname == 'none'
112
- sg_details_list(securitygroup_list, securitygroup_details, securitygroups, filters)
113
-
114
- puts ui.list(securitygroup_list, :columns_across, 3)
115
- puts ui.list(securitygroup_details, :columns_across, 4)
116
- end
117
- end
118
-
119
- end
120
- end
121
-
122
- end
123
- end
124
- end
1
+ # Author:: Jeff Moody (<jmoody@datapipe.com>)
2
+ # Copyright:: Copyright (c) 2012 Datapipe
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+
19
+ require 'chef/knife/cloudstack_base'
20
+
21
+ class Chef
22
+ class Knife
23
+ class CloudstackSecuritygroupList < Knife
24
+
25
+ include Knife::CloudstackBase
26
+
27
+ banner "knife cloudstack securitygroup list (options)"
28
+ option :groupid,
29
+ :short => "-g GROUPID",
30
+ :long => "--groupid GROUPID",
31
+ :description => "List the rules contained within a Security Group, specified by ID",
32
+ :default => 'none'
33
+ option :groupname,
34
+ :short => "-G GROUPNAME",
35
+ :long => "--groupname GROUPNAME",
36
+ :description => "List the rules contained within a Security Group, specified by name.",
37
+ :default => 'none'
38
+
39
+ def sg_details_list(securitygroup_list, securitygroup_details, groups, options={})
40
+ temp = groups
41
+ if groupid = options[:groupid]
42
+ temp.reject!{|g| g['id'] != groupid.to_i}
43
+ end
44
+ if groupname = options[:groupname]
45
+ temp.reject!{|g| g['name'] != groupname}
46
+ end
47
+
48
+ temp.each do |securitygroup|
49
+ securitygroup_list << securitygroup['id'].to_s
50
+ securitygroup_list << securitygroup['name'].to_s
51
+ securitygroup_list << securitygroup['description'].to_s
52
+ if securitygroup['ingressrule'].nil?
53
+ securitygroup_details << ' '
54
+ else
55
+ securitygroup['ingressrule'].each do |ingressrule|
56
+ rule_details = []
57
+ securitygroup_details << ingressrule['protocol'].to_s
58
+ securitygroup_details << ingressrule['startport'].to_s
59
+ securitygroup_details << ingressrule['endport'].to_s
60
+ if ingressrule['cidr'].nil?
61
+ rule_details << ingressrule['securitygroupname'].to_s
62
+ rule_details << ingressrule['account'].to_s
63
+ else
64
+ rule_details << ingressrule['cidr'].to_s
65
+ end
66
+ securitygroup_details << rule_details.join(", ")
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ def run
73
+ $stdout.sync = true
74
+
75
+ validate!
76
+ groupid = locate_config_value(:groupid)
77
+ groupname = locate_config_value(:groupname)
78
+
79
+ if (groupid == 'none' and groupname == 'none')
80
+ securitygroup_list = [
81
+ ui.color('ID', :bold),
82
+ ui.color('Name', :bold),
83
+ ui.color('Description', :bold)
84
+ ]
85
+ response = connection.list_security_groups['listsecuritygroupsresponse']
86
+ if securitygroups = response['securitygroup']
87
+ securitygroups.each do |securitygroup|
88
+ securitygroup_list << securitygroup['id'].to_s
89
+ securitygroup_list << securitygroup['name'].to_s
90
+ securitygroup_list << securitygroup['description'].to_s
91
+ end
92
+ end
93
+ puts ui.list(securitygroup_list, :columns_across, 3)
94
+ else
95
+ securitygroup_details = [
96
+ ui.color('Protocol', :bold),
97
+ ui.color('Start Port', :bold),
98
+ ui.color('End Port', :bold),
99
+ ui.color('Restricted To', :bold)
100
+ ]
101
+ securitygroup_list = [
102
+ ui.color('ID', :bold),
103
+ ui.color('Name', :bold),
104
+ ui.color('Description', :bold)
105
+ ]
106
+
107
+ if response = connection.list_security_groups['listsecuritygroupsresponse']
108
+ if securitygroups = response['securitygroup']
109
+ filters = {}
110
+ filters[:groupid] = groupid unless groupid == 'none'
111
+ filters[:groupname] = groupname unless groupname == 'none'
112
+ sg_details_list(securitygroup_list, securitygroup_details, securitygroups, filters)
113
+
114
+ puts ui.list(securitygroup_list, :columns_across, 3)
115
+ puts ui.list(securitygroup_details, :columns_across, 4)
116
+ end
117
+ end
118
+
119
+ end
120
+ end
121
+
122
+ end
123
+ end
124
+ end
@@ -1,320 +1,320 @@
1
- # Author:: Jeff Moody (<jmoody@datapipe.com>), Takashi Kanai (<anikundesu@gmail.com>)
2
- # Copyright:: Copyright (c) 2012 Datapipe, Copyright (c) 2012 IDC Frontier Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require 'chef/knife/bootstrap'
19
- Chef::Knife::Bootstrap.load_deps
20
- require 'socket'
21
- require 'net/ssh/multi'
22
- require 'chef/json_compat'
23
- require 'chef/knife/cloudstack_base'
24
-
25
- class Chef
26
- class Knife
27
- class CloudstackServerCreate < Knife
28
-
29
- include Knife::CloudstackBase
30
-
31
- banner "knife cloudstack server create -s SERVICEID -t TEMPLATEID -z ZONEID (options)"
32
-
33
- option :cloudstack_serviceid,
34
- :short => "-s SERVICEID",
35
- :long => "--serviceid SERVICEID",
36
- :description => "The CloudStack service offering ID."
37
-
38
- option :cloudstack_templateid,
39
- :short => "-t TEMPLATEID",
40
- :long => "--templateid TEMPLATEID",
41
- :description => "The CloudStack template ID for the server."
42
-
43
- option :cloudstack_zoneid,
44
- :short => "-z ZONEID",
45
- :long => "--zoneid ZONE",
46
- :description => "The CloudStack zone ID for the server."
47
-
48
- option :cloudstack_networkids,
49
- :short => "-w NETWORKIDS",
50
- :long => "--networkids NETWORKIDS",
51
- :description => "Comma separated list of CloudStack network IDs.",
52
- :proc => lambda { |n| n.split(/[\s,]+/) },
53
- :default => []
54
-
55
- option :cloudstack_groupids,
56
- :short => "-g SECURITYGROUPIDS",
57
- :long => "--groupids SECURITYGROUPIDS",
58
- :description => "Comma separated list of CloudStack Security Group IDs.",
59
- :proc => lambda { |n| n.split(/[\s,]+/) },
60
- :default => []
61
-
62
- option :cloudstack_groupnames,
63
- :short => "-G SECURITYGROUPNAMES",
64
- :long => "--groupnames SECURITYGROUPNAMES",
65
- :description => "Comma separated list of CloudStack Security Group names. Each group name must be encapuslated in quotes if it contains whitespace.",
66
- :proc => lambda { |n| n.split(/[\s,]+/) },
67
- :default => []
68
-
69
- option :distro,
70
- :short => "-d DISTRO",
71
- :long => "--distro DISTRO",
72
- :description => "Bootstrap a distro using a template; default is 'chef-full'",
73
- :proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
74
- :default => "chef-full"
75
-
76
- option :template_file,
77
- :long => "--template-file TEMPLATE",
78
- :description => "Full path to location of template to use",
79
- :proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
80
- :default => false
81
-
82
- option :run_list,
83
- :short => "-r RUN_LIST",
84
- :long => "--run-list RUN_LIST",
85
- :description => "Comma separated list of roles/recipes to apply",
86
- :proc => lambda { |o| o.split(/[\s,]+/) },
87
- :default => []
88
-
89
- option :ssh_user,
90
- :short => "-x USERNAME",
91
- :long => "--ssh-user USERNAME",
92
- :description => "The ssh username",
93
- :default => 'root'
94
-
95
- option :ssh_password,
96
- :short => "-P PASSWORD",
97
- :long => "--ssh-password PASSWORD",
98
- :description => "The ssh password"
99
-
100
- option :identity_file,
101
- :short => "-i PRIVATE_KEY_FILE",
102
- :long => "--identity-file PRIVATE_KEY_FILE",
103
- :description => "The Private key file for authenticating SSH session. --keypair option is also needed."
104
-
105
- option :server_name,
106
- :short => "-N NAME",
107
- :long => "--display-name NAME",
108
- :description => "The instance display name"
109
-
110
- option :host_name,
111
- :short => "-H NAME",
112
- :long => "--hostname NAME",
113
- :description => "The instance host name"
114
-
115
- option :keypair,
116
- :short => "-k KEYPAIR",
117
- :long => "--keypair KEYPAIR",
118
- :description => "The CloudStack Key Pair to use for SSH key authentication."
119
-
120
- option :diskoffering,
121
- :short => "-D DISKOFFERINGID",
122
- :long => "--diskoffering DISKOFFERINGID",
123
- :description => "Specifies either the Disk Offering ID for the ROOT disk for an ISO template, or a DATA disk."
124
-
125
- option :size,
126
- :short => "-Z SIZE",
127
- :long => "--size SIZE",
128
- :description => "Specifies the arbitrary Disk Size for DATADISK volume in GB. Must be passed with custom size Disk Offering ID."
129
-
130
- def bootstrap_for_node(host, user, password)
131
- Chef::Log.debug("Bootstrap host: #{host}")
132
- Chef::Log.debug("Bootstrap user: #{user}")
133
- Chef::Log.debug("Bootstrap pass: #{password}")
134
- bootstrap = Chef::Knife::Bootstrap.new
135
- bootstrap.name_args = host
136
- bootstrap.config[:run_list] = config[:run_list]
137
- bootstrap.config[:ssh_user] = user
138
- bootstrap.config[:ssh_password] = password
139
- bootstrap.config[:identity_file] = locate_config_value(:identity_file)
140
- bootstrap.config[:chef_node_name] = config[:server_name] if config[:server_name]
141
- bootstrap.config[:prerelease] = config[:prerelease]
142
- bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
143
- bootstrap.config[:distro] = locate_config_value(:distro)
144
- bootstrap.config[:use_sudo] = true
145
- bootstrap.config[:template_file] = locate_config_value(:template_file)
146
- bootstrap.config[:environment] = config[:environment]
147
- # may be needed for vpc_mode
148
- bootstrap.config[:no_host_key_verify] = config[:no_host_key_verify]
149
- bootstrap
150
- end
151
-
152
- def tcp_test_ssh(hostname)
153
- print("#{ui.color(".", :magenta)}")
154
- tcp_socket = TCPSocket.new(hostname, 22)
155
- readable = IO.select([tcp_socket], nil, nil, 5)
156
- if readable
157
- Chef::Log.debug("\nsshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}\n")
158
- yield
159
- true
160
- else
161
- false
162
- end
163
-
164
- rescue Errno::ETIMEDOUT
165
- false
166
- rescue Errno::EPERM
167
- false
168
- rescue Errno::ECONNREFUSED
169
- sleep 2
170
- false
171
- rescue Errno::EHOSTUNREACH
172
- sleep 2
173
- false
174
- rescue Errno::ENETUNREACH
175
- sleep 30
176
- false
177
- ensure
178
- tcp_socket && tcp_socket.close
179
- end
180
-
181
- def run
182
- $stdout.sync = true
183
-
184
- options = {}
185
-
186
- options['zoneid'] = locate_config_value(:cloudstack_zoneid)
187
- options['templateid'] = locate_config_value(:cloudstack_templateid)
188
-
189
- if locate_config_value(:cloudstack_serviceid) != nil
190
- options['serviceofferingid'] = locate_config_value(:cloudstack_serviceid)
191
- end
192
-
193
- if locate_config_value(:server_name) != nil
194
- options['displayname'] = locate_config_value(:server_name)
195
- end
196
-
197
- if locate_config_value(:host_name) != nil
198
- options['name'] = locate_config_value(:host_name)
199
- end
200
-
201
- network_ids = []
202
- if locate_config_value(:cloudstack_networkids) != []
203
- cs_networkids = locate_config_value(:cloudstack_networkids)
204
- cs_networkids.each do |id|
205
- network_ids.push(id)
206
- end
207
- options['networkids'] = network_ids
208
- end
209
-
210
- security_groups = []
211
- if locate_config_value(:cloudstack_groupids) != []
212
- cs_groupids = locate_config_value(:cloudstack_groupids)
213
- cs_groupids.each do |id|
214
- security_groups.push(id)
215
- end
216
- options['securitygroupids'] = security_groups
217
- elsif locate_config_value(:cloudstack_groupnames) != []
218
- cs_groupnames = locate_config_value(:cloudstack_groupnames)
219
- cs_groupnames.each do |name|
220
- security_groups.push(name)
221
- end
222
- options['securitygroupnames'] = security_groups
223
- end
224
-
225
- if locate_config_value(:keypair) != nil
226
- options['keypair'] = locate_config_value(:keypair)
227
- end
228
-
229
- if locate_config_value(:diskoffering) != nil
230
- options['diskofferingid'] = locate_config_value(:diskoffering)
231
- end
232
-
233
- if locate_config_value(:size) != nil
234
- options['size'] = locate_config_value(:size)
235
- end
236
-
237
- Chef::Log.debug("Options: #{options} \n")
238
-
239
- server = connection.deploy_virtual_machine(options)
240
- jobid = server['deployvirtualmachineresponse'].fetch('jobid')
241
-
242
- server_start = connection.query_async_job_result('jobid'=>jobid)
243
-
244
- Chef::Log.debug("Job ID: #{jobid} \n")
245
-
246
- print "#{ui.color("Waiting for server", :magenta)}"
247
- while server_start['queryasyncjobresultresponse'].fetch('jobstatus') == 0
248
- print "#{ui.color(".", :magenta)}"
249
- sleep(15)
250
- server_start = connection.query_async_job_result('jobid'=>jobid)
251
- Chef::Log.debug("Server_Start: #{server_start} \n")
252
- end
253
- puts "\n\n"
254
-
255
- if server_start['queryasyncjobresultresponse'].fetch('jobstatus') == 2
256
- errortext = server_start['queryasyncjobresultresponse'].fetch('jobresult').fetch('errortext')
257
- puts "#{ui.color("ERROR! Job failed with #{errortext}", :red)}"
258
- end
259
-
260
- if server_start['queryasyncjobresultresponse'].fetch('jobstatus') == 1
261
-
262
- Chef::Log.debug("Job ID: #{jobid} \n")
263
- Chef::Log.debug("Options: #{options} \n")
264
- server_start = connection.query_async_job_result('jobid'=>jobid)
265
- Chef::Log.debug("Server_Start: #{server_start} \n")
266
-
267
- server_info = server_start['queryasyncjobresultresponse']['jobresult']['virtualmachine']
268
-
269
- server_name = server_info['displayname']
270
- server_id = server_info['name']
271
- server_serviceoffering = server_info['serviceofferingname']
272
- server_template = server_info['templatename']
273
- if server_info['password'] != nil
274
- ssh_password = server_info['password']
275
- else
276
- ssh_password = locate_config_value(:ssh_password)
277
- end
278
-
279
- ssh_user = locate_config_value(:ssh_user)
280
-
281
- public_ip = nil
282
-
283
- if server_info['nic'].size > 0
284
- public_ip = server_info['nic'].first['ipaddress']
285
- end
286
-
287
- puts "\n\n"
288
- puts "#{ui.color("Name", :cyan)}: #{server_name}"
289
- puts "#{ui.color("Public IP", :cyan)}: #{public_ip}"
290
- puts "#{ui.color("Username", :cyan)}: #{ssh_user}"
291
- puts "#{ui.color("Password", :cyan)}: #{ssh_password}"
292
-
293
- print "\n#{ui.color("Waiting for sshd", :magenta)}"
294
-
295
- print("#{ui.color(".", :magenta)}") until tcp_test_ssh(public_ip) { sleep @initial_sleep_delay ||= 10; puts("done") }
296
-
297
- puts("#{ui.color("Waiting for password/keys to sync.", :magenta)}")
298
- sleep 15
299
-
300
- bootstrap_for_node(public_ip, ssh_user, ssh_password).run
301
-
302
- Chef::Log.debug("#{server_info}")
303
-
304
- puts "\n"
305
- puts "#{ui.color("Instance Name", :green)}: #{server_name}"
306
- puts "#{ui.color("Instance ID", :green)}: #{server_id}"
307
- puts "#{ui.color("Service Offering", :green)}: #{server_serviceoffering}"
308
- puts "#{ui.color("Template", :green)}: #{server_template}"
309
- puts "#{ui.color("Public IP Address", :green)}: #{public_ip}"
310
- puts "#{ui.color("User", :green)}: #{ssh_user}"
311
- puts "#{ui.color("Password", :green)}: #{ssh_password}"
312
- puts "#{ui.color("Environment", :green)}: #{config[:environment] || '_default'}"
313
- puts "#{ui.color("Run List", :green)}: #{config[:run_list].join(', ')}"
314
- end
315
-
316
- end
317
-
318
- end
319
- end
320
- end
1
+ # Author:: Jeff Moody (<jmoody@datapipe.com>), Takashi Kanai (<anikundesu@gmail.com>)
2
+ # Copyright:: Copyright (c) 2012 Datapipe, Copyright (c) 2012 IDC Frontier Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife/bootstrap'
19
+ Chef::Knife::Bootstrap.load_deps
20
+ require 'socket'
21
+ require 'net/ssh/multi'
22
+ require 'chef/json_compat'
23
+ require 'chef/knife/cloudstack_base'
24
+
25
+ class Chef
26
+ class Knife
27
+ class CloudstackServerCreate < Knife
28
+
29
+ include Knife::CloudstackBase
30
+
31
+ banner "knife cloudstack server create -s SERVICEID -t TEMPLATEID -z ZONEID (options)"
32
+
33
+ option :cloudstack_serviceid,
34
+ :short => "-s SERVICEID",
35
+ :long => "--serviceid SERVICEID",
36
+ :description => "The CloudStack service offering ID."
37
+
38
+ option :cloudstack_templateid,
39
+ :short => "-t TEMPLATEID",
40
+ :long => "--templateid TEMPLATEID",
41
+ :description => "The CloudStack template ID for the server."
42
+
43
+ option :cloudstack_zoneid,
44
+ :short => "-z ZONEID",
45
+ :long => "--zoneid ZONE",
46
+ :description => "The CloudStack zone ID for the server."
47
+
48
+ option :cloudstack_networkids,
49
+ :short => "-w NETWORKIDS",
50
+ :long => "--networkids NETWORKIDS",
51
+ :description => "Comma separated list of CloudStack network IDs.",
52
+ :proc => lambda { |n| n.split(/[\s,]+/) },
53
+ :default => []
54
+
55
+ option :cloudstack_groupids,
56
+ :short => "-g SECURITYGROUPIDS",
57
+ :long => "--groupids SECURITYGROUPIDS",
58
+ :description => "Comma separated list of CloudStack Security Group IDs.",
59
+ :proc => lambda { |n| n.split(/[\s,]+/) },
60
+ :default => []
61
+
62
+ option :cloudstack_groupnames,
63
+ :short => "-G SECURITYGROUPNAMES",
64
+ :long => "--groupnames SECURITYGROUPNAMES",
65
+ :description => "Comma separated list of CloudStack Security Group names. Each group name must be encapuslated in quotes if it contains whitespace.",
66
+ :proc => lambda { |n| n.split(/[\s,]+/) },
67
+ :default => []
68
+
69
+ option :distro,
70
+ :short => "-d DISTRO",
71
+ :long => "--distro DISTRO",
72
+ :description => "Bootstrap a distro using a template; default is 'chef-full'",
73
+ :proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
74
+ :default => "chef-full"
75
+
76
+ option :template_file,
77
+ :long => "--template-file TEMPLATE",
78
+ :description => "Full path to location of template to use",
79
+ :proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
80
+ :default => false
81
+
82
+ option :run_list,
83
+ :short => "-r RUN_LIST",
84
+ :long => "--run-list RUN_LIST",
85
+ :description => "Comma separated list of roles/recipes to apply",
86
+ :proc => lambda { |o| o.split(/[\s,]+/) },
87
+ :default => []
88
+
89
+ option :ssh_user,
90
+ :short => "-x USERNAME",
91
+ :long => "--ssh-user USERNAME",
92
+ :description => "The ssh username",
93
+ :default => 'root'
94
+
95
+ option :ssh_password,
96
+ :short => "-P PASSWORD",
97
+ :long => "--ssh-password PASSWORD",
98
+ :description => "The ssh password"
99
+
100
+ option :identity_file,
101
+ :short => "-i PRIVATE_KEY_FILE",
102
+ :long => "--identity-file PRIVATE_KEY_FILE",
103
+ :description => "The Private key file for authenticating SSH session. --keypair option is also needed."
104
+
105
+ option :server_name,
106
+ :short => "-N NAME",
107
+ :long => "--display-name NAME",
108
+ :description => "The instance display name"
109
+
110
+ option :host_name,
111
+ :short => "-H NAME",
112
+ :long => "--hostname NAME",
113
+ :description => "The instance host name"
114
+
115
+ option :keypair,
116
+ :short => "-k KEYPAIR",
117
+ :long => "--keypair KEYPAIR",
118
+ :description => "The CloudStack Key Pair to use for SSH key authentication."
119
+
120
+ option :diskoffering,
121
+ :short => "-D DISKOFFERINGID",
122
+ :long => "--diskoffering DISKOFFERINGID",
123
+ :description => "Specifies either the Disk Offering ID for the ROOT disk for an ISO template, or a DATA disk."
124
+
125
+ option :size,
126
+ :short => "-Z SIZE",
127
+ :long => "--size SIZE",
128
+ :description => "Specifies the arbitrary Disk Size for DATADISK volume in GB. Must be passed with custom size Disk Offering ID."
129
+
130
+ def bootstrap_for_node(host, user, password)
131
+ Chef::Log.debug("Bootstrap host: #{host}")
132
+ Chef::Log.debug("Bootstrap user: #{user}")
133
+ Chef::Log.debug("Bootstrap pass: #{password}")
134
+ bootstrap = Chef::Knife::Bootstrap.new
135
+ bootstrap.name_args = host
136
+ bootstrap.config[:run_list] = config[:run_list]
137
+ bootstrap.config[:ssh_user] = user
138
+ bootstrap.config[:ssh_password] = password
139
+ bootstrap.config[:identity_file] = locate_config_value(:identity_file)
140
+ bootstrap.config[:chef_node_name] = config[:server_name] if config[:server_name]
141
+ bootstrap.config[:prerelease] = config[:prerelease]
142
+ bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
143
+ bootstrap.config[:distro] = locate_config_value(:distro)
144
+ bootstrap.config[:use_sudo] = true
145
+ bootstrap.config[:template_file] = locate_config_value(:template_file)
146
+ bootstrap.config[:environment] = config[:environment]
147
+ # may be needed for vpc_mode
148
+ bootstrap.config[:no_host_key_verify] = config[:no_host_key_verify]
149
+ bootstrap
150
+ end
151
+
152
+ def tcp_test_ssh(hostname)
153
+ print("#{ui.color(".", :magenta)}")
154
+ tcp_socket = TCPSocket.new(hostname, 22)
155
+ readable = IO.select([tcp_socket], nil, nil, 5)
156
+ if readable
157
+ Chef::Log.debug("\nsshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}\n")
158
+ yield
159
+ true
160
+ else
161
+ false
162
+ end
163
+
164
+ rescue Errno::ETIMEDOUT
165
+ false
166
+ rescue Errno::EPERM
167
+ false
168
+ rescue Errno::ECONNREFUSED
169
+ sleep 2
170
+ false
171
+ rescue Errno::EHOSTUNREACH
172
+ sleep 2
173
+ false
174
+ rescue Errno::ENETUNREACH
175
+ sleep 30
176
+ false
177
+ ensure
178
+ tcp_socket && tcp_socket.close
179
+ end
180
+
181
+ def run
182
+ $stdout.sync = true
183
+
184
+ options = {}
185
+
186
+ options['zoneid'] = locate_config_value(:cloudstack_zoneid)
187
+ options['templateid'] = locate_config_value(:cloudstack_templateid)
188
+
189
+ if locate_config_value(:cloudstack_serviceid) != nil
190
+ options['serviceofferingid'] = locate_config_value(:cloudstack_serviceid)
191
+ end
192
+
193
+ if locate_config_value(:server_name) != nil
194
+ options['displayname'] = locate_config_value(:server_name)
195
+ end
196
+
197
+ if locate_config_value(:host_name) != nil
198
+ options['name'] = locate_config_value(:host_name)
199
+ end
200
+
201
+ network_ids = []
202
+ if locate_config_value(:cloudstack_networkids) != []
203
+ cs_networkids = locate_config_value(:cloudstack_networkids)
204
+ cs_networkids.each do |id|
205
+ network_ids.push(id)
206
+ end
207
+ options['networkids'] = network_ids
208
+ end
209
+
210
+ security_groups = []
211
+ if locate_config_value(:cloudstack_groupids) != []
212
+ cs_groupids = locate_config_value(:cloudstack_groupids)
213
+ cs_groupids.each do |id|
214
+ security_groups.push(id)
215
+ end
216
+ options['securitygroupids'] = security_groups
217
+ elsif locate_config_value(:cloudstack_groupnames) != []
218
+ cs_groupnames = locate_config_value(:cloudstack_groupnames)
219
+ cs_groupnames.each do |name|
220
+ security_groups.push(name)
221
+ end
222
+ options['securitygroupnames'] = security_groups
223
+ end
224
+
225
+ if locate_config_value(:keypair) != nil
226
+ options['keypair'] = locate_config_value(:keypair)
227
+ end
228
+
229
+ if locate_config_value(:diskoffering) != nil
230
+ options['diskofferingid'] = locate_config_value(:diskoffering)
231
+ end
232
+
233
+ if locate_config_value(:size) != nil
234
+ options['size'] = locate_config_value(:size)
235
+ end
236
+
237
+ Chef::Log.debug("Options: #{options} \n")
238
+
239
+ server = connection.deploy_virtual_machine(options)
240
+ jobid = server['deployvirtualmachineresponse'].fetch('jobid')
241
+
242
+ server_start = connection.query_async_job_result('jobid'=>jobid)
243
+
244
+ Chef::Log.debug("Job ID: #{jobid} \n")
245
+
246
+ print "#{ui.color("Waiting for server", :magenta)}"
247
+ while server_start['queryasyncjobresultresponse'].fetch('jobstatus') == 0
248
+ print "#{ui.color(".", :magenta)}"
249
+ sleep(15)
250
+ server_start = connection.query_async_job_result('jobid'=>jobid)
251
+ Chef::Log.debug("Server_Start: #{server_start} \n")
252
+ end
253
+ puts "\n\n"
254
+
255
+ if server_start['queryasyncjobresultresponse'].fetch('jobstatus') == 2
256
+ errortext = server_start['queryasyncjobresultresponse'].fetch('jobresult').fetch('errortext')
257
+ puts "#{ui.color("ERROR! Job failed with #{errortext}", :red)}"
258
+ end
259
+
260
+ if server_start['queryasyncjobresultresponse'].fetch('jobstatus') == 1
261
+
262
+ Chef::Log.debug("Job ID: #{jobid} \n")
263
+ Chef::Log.debug("Options: #{options} \n")
264
+ server_start = connection.query_async_job_result('jobid'=>jobid)
265
+ Chef::Log.debug("Server_Start: #{server_start} \n")
266
+
267
+ server_info = server_start['queryasyncjobresultresponse']['jobresult']['virtualmachine']
268
+
269
+ server_name = server_info['displayname']
270
+ server_id = server_info['name']
271
+ server_serviceoffering = server_info['serviceofferingname']
272
+ server_template = server_info['templatename']
273
+ if server_info['password'] != nil
274
+ ssh_password = server_info['password']
275
+ else
276
+ ssh_password = locate_config_value(:ssh_password)
277
+ end
278
+
279
+ ssh_user = locate_config_value(:ssh_user)
280
+
281
+ public_ip = nil
282
+
283
+ if server_info['nic'].size > 0
284
+ public_ip = server_info['nic'].first['ipaddress']
285
+ end
286
+
287
+ puts "\n\n"
288
+ puts "#{ui.color("Name", :cyan)}: #{server_name}"
289
+ puts "#{ui.color("Public IP", :cyan)}: #{public_ip}"
290
+ puts "#{ui.color("Username", :cyan)}: #{ssh_user}"
291
+ puts "#{ui.color("Password", :cyan)}: #{ssh_password}"
292
+
293
+ print "\n#{ui.color("Waiting for sshd", :magenta)}"
294
+
295
+ print("#{ui.color(".", :magenta)}") until tcp_test_ssh(public_ip) { sleep @initial_sleep_delay ||= 10; puts("done") }
296
+
297
+ puts("#{ui.color("Waiting for password/keys to sync.", :magenta)}")
298
+ sleep 15
299
+
300
+ bootstrap_for_node(public_ip, ssh_user, ssh_password).run
301
+
302
+ Chef::Log.debug("#{server_info}")
303
+
304
+ puts "\n"
305
+ puts "#{ui.color("Instance Name", :green)}: #{server_name}"
306
+ puts "#{ui.color("Instance ID", :green)}: #{server_id}"
307
+ puts "#{ui.color("Service Offering", :green)}: #{server_serviceoffering}"
308
+ puts "#{ui.color("Template", :green)}: #{server_template}"
309
+ puts "#{ui.color("Public IP Address", :green)}: #{public_ip}"
310
+ puts "#{ui.color("User", :green)}: #{ssh_user}"
311
+ puts "#{ui.color("Password", :green)}: #{ssh_password}"
312
+ puts "#{ui.color("Environment", :green)}: #{config[:environment] || '_default'}"
313
+ puts "#{ui.color("Run List", :green)}: #{config[:run_list].join(', ')}"
314
+ end
315
+
316
+ end
317
+
318
+ end
319
+ end
320
+ end