knife-cloudstack 0.0.13 → 0.0.14

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.
Files changed (38) hide show
  1. data/CHANGES.rdoc +50 -0
  2. data/README.rdoc +221 -42
  3. data/lib/chef/knife/cs_account_list.rb +130 -0
  4. data/lib/chef/knife/cs_base.rb +98 -0
  5. data/lib/chef/knife/cs_baselist.rb +81 -0
  6. data/lib/chef/knife/cs_cluster_list.rb +93 -0
  7. data/lib/chef/knife/cs_config_list.rb +85 -0
  8. data/lib/chef/knife/cs_disk_list.rb +89 -0
  9. data/lib/chef/knife/cs_domain_list.rb +83 -0
  10. data/lib/chef/knife/cs_firewallrule_list.rb +95 -0
  11. data/lib/chef/knife/cs_host_list.rb +95 -0
  12. data/lib/chef/knife/cs_hosts.rb +2 -2
  13. data/lib/chef/knife/cs_iso_list.rb +103 -0
  14. data/lib/chef/knife/cs_network_list.rb +56 -46
  15. data/lib/chef/knife/cs_oscategory_list.rb +78 -0
  16. data/lib/chef/knife/cs_ostype_list.rb +80 -0
  17. data/lib/chef/knife/cs_pod_list.rb +93 -0
  18. data/lib/chef/knife/cs_project_list.rb +92 -0
  19. data/lib/chef/knife/cs_router_list.rb +94 -0
  20. data/lib/chef/knife/cs_server_create.rb +185 -144
  21. data/lib/chef/knife/cs_server_delete.rb +62 -79
  22. data/lib/chef/knife/cs_server_list.rb +136 -57
  23. data/lib/chef/knife/cs_server_reboot.rb +50 -54
  24. data/lib/chef/knife/cs_server_start.rb +48 -52
  25. data/lib/chef/knife/cs_server_stop.rb +54 -55
  26. data/lib/chef/knife/cs_service_list.rb +62 -41
  27. data/lib/chef/knife/cs_stack_create.rb +2 -2
  28. data/lib/chef/knife/cs_stack_delete.rb +2 -2
  29. data/lib/chef/knife/cs_template_create.rb +121 -0
  30. data/lib/chef/knife/cs_template_extract.rb +104 -0
  31. data/lib/chef/knife/cs_template_list.rb +65 -63
  32. data/lib/chef/knife/cs_template_register.rb +180 -0
  33. data/lib/chef/knife/cs_user_list.rb +93 -0
  34. data/lib/chef/knife/cs_volume_list.rb +94 -0
  35. data/lib/chef/knife/cs_zone_list.rb +55 -36
  36. data/lib/knife-cloudstack/connection.rb +75 -22
  37. data/lib/knife-cloudstack/string_to_regexp.rb +32 -0
  38. metadata +93 -61
@@ -0,0 +1,78 @@
1
+ #
2
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
3
+ # Copyright:: Copyright (c) 2013 Sander Botman.
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/cs_base'
20
+ require 'chef/knife/cs_baselist'
21
+
22
+ module KnifeCloudstack
23
+ class CsOscategoryList < Chef::Knife
24
+
25
+ include Chef::Knife::KnifeCloudstackBase
26
+ include Chef::Knife::KnifeCloudstackBaseList
27
+
28
+ deps do
29
+ require 'knife-cloudstack/connection'
30
+ Chef::Knife.load_deps
31
+ end
32
+
33
+ banner "knife cs oscategory list (options)"
34
+
35
+ option :keyword,
36
+ :long => "--keyword KEY",
37
+ :description => "List by keyword"
38
+
39
+ def run
40
+ validate_base_options
41
+
42
+ if locate_config_value(:fields)
43
+ object_list = []
44
+ locate_config_value(:fields).split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
45
+ else
46
+ object_list = [
47
+ ui.color('Name', :bold),
48
+ ui.color('ID', :bold),
49
+ ]
50
+ end
51
+
52
+ columns = object_list.count
53
+ object_list = [] if locate_config_value(:noheader)
54
+
55
+ connection_result = connection.list_object(
56
+ "listOsCategories",
57
+ "oscategory",
58
+ locate_config_value(:filter),
59
+ false,
60
+ locate_config_value(:keyword)
61
+ )
62
+
63
+ output_format(connection_result)
64
+
65
+ connection_result.each do |r|
66
+ if locate_config_value(:fields)
67
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
68
+ else
69
+ object_list << r['name'].to_s
70
+ object_list << r['id'].to_s
71
+ end
72
+ end
73
+ puts ui.list(object_list, :uneven_columns_across, columns)
74
+ list_object_fields(connection_result) if locate_config_value(:fieldlist)
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,80 @@
1
+ #
2
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
3
+ # Copyright:: Copyright (c) 2013 Sander Botman.
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/cs_base'
20
+ require 'chef/knife/cs_baselist'
21
+
22
+ module KnifeCloudstack
23
+ class CsOstypeList < Chef::Knife
24
+
25
+ include Chef::Knife::KnifeCloudstackBase
26
+ include Chef::Knife::KnifeCloudstackBaseList
27
+
28
+ deps do
29
+ require 'knife-cloudstack/connection'
30
+ Chef::Knife.load_deps
31
+ end
32
+
33
+ banner "knife cs ostype list (options)"
34
+
35
+ option :keyword,
36
+ :long => "--keyword KEY",
37
+ :description => "List by keyword"
38
+
39
+ def run
40
+ validate_base_options
41
+
42
+ if locate_config_value(:fields)
43
+ object_list = []
44
+ locate_config_value(:fields).split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
45
+ else
46
+ object_list = [
47
+ ui.color('ID', :bold),
48
+ ui.color('Description', :bold),
49
+ ui.color('OS Categorie ID', :bold)
50
+ ]
51
+ end
52
+
53
+ columns = object_list.count
54
+ object_list = [] if locate_config_value(:noheader)
55
+
56
+ connection_result = connection.list_object(
57
+ "listOsTypes",
58
+ "ostype",
59
+ locate_config_value(:filter),
60
+ false,
61
+ locate_config_value(:keyword)
62
+ )
63
+
64
+ output_format(connection_result)
65
+
66
+ connection_result.each do |r|
67
+ if locate_config_value(:fields)
68
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
69
+ else
70
+ object_list << r['id'].to_s
71
+ object_list << r['description'].to_s
72
+ object_list << r['oscategoryid'].to_s
73
+ end
74
+ end
75
+ puts ui.list(object_list, :uneven_columns_across, columns)
76
+ list_object_fields(connection_result) if locate_config_value(:fieldlist)
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,93 @@
1
+ #
2
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
3
+ # Copyright:: Copyright (c) 2013 Sander Botman.
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/cs_base'
20
+ require 'chef/knife/cs_baselist'
21
+
22
+ module KnifeCloudstack
23
+ class CsPodList < Chef::Knife
24
+
25
+ include Chef::Knife::KnifeCloudstackBase
26
+ include Chef::Knife::KnifeCloudstackBaseList
27
+
28
+ deps do
29
+ require 'knife-cloudstack/connection'
30
+ Chef::Knife.load_deps
31
+ end
32
+
33
+ banner "knife cs pod list (options)"
34
+
35
+ option :name,
36
+ :long => "--name NAME",
37
+ :description => "Specify router pod to list"
38
+
39
+ option :keyword,
40
+ :long => "--keyword KEY",
41
+ :description => "List by keyword"
42
+
43
+ def run
44
+ validate_base_options
45
+
46
+ if locate_config_value(:fields)
47
+ object_list = []
48
+ locate_config_value(:fields).split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
49
+ else
50
+ object_list = [
51
+ ui.color('Name', :bold),
52
+ ui.color('Zone', :bold),
53
+ ui.color('Gateway', :bold),
54
+ ui.color('Netmask', :bold),
55
+ ui.color('Start IP', :bold),
56
+ ui.color('End IP', :bold),
57
+ ui.color('AllocationState', :bold)
58
+ ]
59
+ end
60
+
61
+ columns = object_list.count
62
+ object_list = [] if locate_config_value(:noheader)
63
+
64
+ connection_result = connection.list_object(
65
+ "listPods",
66
+ "pod",
67
+ locate_config_value(:filter),
68
+ false,
69
+ locate_config_value(:keyword),
70
+ locate_config_value(:name)
71
+ )
72
+
73
+ output_format(connection_result)
74
+
75
+ connection_result.each do |r|
76
+ if locate_config_value(:fields)
77
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
78
+ else
79
+ object_list << r['name'].to_s
80
+ object_list << r['zonename'].to_s
81
+ object_list << r['gateway'].to_s
82
+ object_list << r['netmask'].to_s
83
+ object_list << r['startip'].to_s
84
+ object_list << r['endip'].to_s
85
+ object_list << r['allocationstate'].to_s
86
+ end
87
+ end
88
+ puts ui.list(object_list, :uneven_columns_across, columns)
89
+ list_object_fields(connection_result) if locate_config_value(:fieldlist)
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,92 @@
1
+ #
2
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
3
+ # Copyright:: Copyright (c) 2013 Sander Botman.
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/cs_base'
20
+ require 'chef/knife/cs_baselist'
21
+
22
+ module KnifeCloudstack
23
+ class CsProjectList < Chef::Knife
24
+
25
+ include Chef::Knife::KnifeCloudstackBase
26
+ include Chef::Knife::KnifeCloudstackBaseList
27
+
28
+ deps do
29
+ require 'knife-cloudstack/connection'
30
+ Chef::Knife.load_deps
31
+ end
32
+
33
+ banner "knife cs project list (options)"
34
+
35
+ option :listall,
36
+ :long => "--listall",
37
+ :description => "List all projects",
38
+ :boolean => true
39
+
40
+ option :name,
41
+ :long => "--name NAME",
42
+ :description => "Specify project name to list"
43
+
44
+ option :keyword,
45
+ :long => "--keyword KEY",
46
+ :description => "List by keyword"
47
+
48
+ def run
49
+ validate_base_options
50
+
51
+ if locate_config_value(:fields)
52
+ object_list = []
53
+ locate_config_value(:fields).split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
54
+ else
55
+ object_list = [
56
+ ui.color('Name', :bold),
57
+ ui.color('Account', :bold),
58
+ ui.color('Domain', :bold),
59
+ ui.color('State', :bold),
60
+ ]
61
+ end
62
+
63
+ columns = object_list.count
64
+ object_list = [] if locate_config_value(:noheader)
65
+
66
+ connection_result = connection.list_object(
67
+ "listProjects",
68
+ "project",
69
+ locate_config_value(:filter),
70
+ locate_config_value(:listall),
71
+ locate_config_value(:keyword),
72
+ locate_config_value(:name)
73
+ )
74
+
75
+ output_format(connection_result)
76
+
77
+ connection_result.each do |r|
78
+ if locate_config_value(:fields)
79
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
80
+ else
81
+ object_list << r['name'].to_s
82
+ object_list << r['account'].to_s
83
+ object_list << r['domain'].to_s
84
+ object_list << r['state'].to_s
85
+ end
86
+ end
87
+ puts ui.list(object_list, :uneven_columns_across, columns)
88
+ list_object_fields(connection_result) if locate_config_value(:fieldlist)
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,94 @@
1
+ #
2
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
3
+ # Copyright:: Copyright (c) 2013 Sander Botman.
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/cs_base'
20
+ require 'chef/knife/cs_baselist'
21
+
22
+ module KnifeCloudstack
23
+ class CsRouterList < Chef::Knife
24
+
25
+ include Chef::Knife::KnifeCloudstackBase
26
+ include Chef::Knife::KnifeCloudstackBaseList
27
+
28
+ deps do
29
+ require 'knife-cloudstack/connection'
30
+ Chef::Knife.load_deps
31
+ end
32
+
33
+ banner "knife cs router list (options)"
34
+
35
+ option :listall,
36
+ :long => "--listall",
37
+ :description => "List all routers",
38
+ :boolean => true
39
+
40
+ option :name,
41
+ :long => "--name NAME",
42
+ :description => "Specify router name to list"
43
+
44
+ option :keyword,
45
+ :long => "--keyword KEY",
46
+ :description => "List by keyword"
47
+
48
+ def run
49
+ validate_base_options
50
+
51
+ if locate_config_value(:fields)
52
+ object_list = []
53
+ locate_config_value(:fields).split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
54
+ else
55
+ object_list = [
56
+ ui.color('Name', :bold),
57
+ ui.color('Account', :bold),
58
+ ui.color('Domain', :bold),
59
+ ui.color('State', :bold),
60
+ ui.color('Address', :bold)
61
+ ]
62
+ end
63
+
64
+ columns = object_list.count
65
+ object_list = [] if locate_config_value(:noheader)
66
+
67
+ connection_result = connection.list_object(
68
+ "listRouters",
69
+ "router",
70
+ locate_config_value(:filter),
71
+ locate_config_value(:listall),
72
+ locate_config_value(:keyword),
73
+ locate_config_value(:name)
74
+ )
75
+
76
+ output_format(connection_result)
77
+
78
+ connection_result.each do |r|
79
+ if locate_config_value(:fields)
80
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
81
+ else
82
+ object_list << r['name'].to_s
83
+ object_list << r['account'].to_s
84
+ object_list << r['domain'].to_s
85
+ object_list << r['state'].to_s
86
+ object_list << r['publicip'].to_s
87
+ end
88
+ end
89
+ puts ui.list(object_list, :uneven_columns_across, columns)
90
+ list_object_fields(connection_result) if locate_config_value(:fieldlist)
91
+ end
92
+
93
+ end
94
+ end
@@ -1,6 +1,8 @@
1
1
  #
2
2
  # Author:: Ryan Holmes (<rholmes@edmunds.com>)
3
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
3
4
  # Copyright:: Copyright (c) 2011 Edmunds, Inc.
5
+ # Copyright:: Copyright (c) 2013 Sander Botman.
4
6
  # License:: Apache License, Version 2.0
5
7
  #
6
8
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +18,13 @@
16
18
  # limitations under the License.
17
19
  #
18
20
 
19
- require 'chef/knife'
20
- require 'json'
21
+ require 'chef/knife/cs_base'
21
22
  require 'chef/knife/winrm_base'
22
- require 'winrm'
23
- require 'httpclient'
24
- require 'em-winrm'
25
-
26
23
 
27
24
  module KnifeCloudstack
28
25
  class CsServerCreate < Chef::Knife
29
26
 
27
+ include Chef::Knife::KnifeCloudstackBase
30
28
  include Chef::Knife::WinrmBase
31
29
 
32
30
  # Seconds to delay between detecting ssh and initiating the bootstrap
@@ -43,11 +41,16 @@ module KnifeCloudstack
43
41
  require 'chef/knife/bootstrap_windows_ssh'
44
42
  require 'chef/knife/core/windows_bootstrap_context'
45
43
  require 'chef/knife/winrm'
46
- Chef::Knife::Bootstrap.load_deps
47
44
  require 'socket'
48
45
  require 'net/ssh/multi'
46
+ require 'chef/knife'
47
+ require 'chef/knife/bootstrap'
49
48
  require 'chef/json_compat'
50
49
  require 'knife-cloudstack/connection'
50
+ require 'winrm'
51
+ require 'httpclient'
52
+ require 'em-winrm'
53
+ Chef::Knife::Bootstrap.load_deps
51
54
  end
52
55
 
53
56
  banner "knife cs server create [SERVER_NAME] (options)"
@@ -78,6 +81,15 @@ module KnifeCloudstack
78
81
  :proc => lambda { |n| n.split(',').map {|sn| sn.strip}} ,
79
82
  :default => []
80
83
 
84
+ option :cloudstack_hypervisor,
85
+ :long => '--cloudstack-hypervisor HYPERVISOR',
86
+ :description => "The CloudStack hypervisor type for the server"
87
+
88
+ option :cloudstack_password,
89
+ :long => "--cloudstack-password",
90
+ :description => "Enables auto-generated passwords by Cloudstack",
91
+ :boolean => true
92
+
81
93
  option :public_ip,
82
94
  :long => "--[no-]public-ip",
83
95
  :description => "Allocate a public IP for this server",
@@ -99,7 +111,6 @@ module KnifeCloudstack
99
111
  :long => "--ssh-password PASSWORD",
100
112
  :description => "The ssh password"
101
113
 
102
-
103
114
  option :ssh_port,
104
115
  :long => "--ssh-port PORT",
105
116
  :description => "The ssh port",
@@ -110,24 +121,6 @@ module KnifeCloudstack
110
121
  :long => "--identity-file IDENTITY_FILE",
111
122
  :description => "The SSH identity file used for authentication"
112
123
 
113
- option :cloudstack_url,
114
- :short => "-U URL",
115
- :long => "--cloudstack-url URL",
116
- :description => "The CloudStack API endpoint URL",
117
- :proc => Proc.new { |u| Chef::Config[:knife][:cloudstack_url] = u }
118
-
119
- option :cloudstack_api_key,
120
- :short => "-A KEY",
121
- :long => "--cloudstack-api-key KEY",
122
- :description => "Your CloudStack API key",
123
- :proc => Proc.new { |k| Chef::Config[:knife][:cloudstack_api_key] = k }
124
-
125
- option :cloudstack_secret_key,
126
- :short => "-K SECRET",
127
- :long => "--cloudstack-secret-key SECRET",
128
- :description => "Your CloudStack secret key",
129
- :proc => Proc.new { |s| Chef::Config[:knife][:cloudstack_secret_key] = s }
130
-
131
124
  option :prerelease,
132
125
  :long => "--prerelease",
133
126
  :description => "Install the pre-release chef gems"
@@ -142,7 +135,7 @@ module KnifeCloudstack
142
135
  :long => "--distro DISTRO",
143
136
  :description => "Bootstrap a distro using a template",
144
137
  :proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
145
- :default => "ubuntu10.04-gems"
138
+ :default => "chef-full"
146
139
 
147
140
  option :template_file,
148
141
  :long => "--template-file TEMPLATE",
@@ -163,11 +156,11 @@ module KnifeCloudstack
163
156
  :boolean => true,
164
157
  :default => false
165
158
 
166
- option :no_bootstrap,
167
- :long => "--no-bootstrap",
159
+ option :bootstrap,
160
+ :long => "--[no-]bootstrap",
168
161
  :description => "Disable Chef bootstrap",
169
162
  :boolean => true,
170
- :default => false
163
+ :default => true
171
164
 
172
165
  option :port_rules,
173
166
  :short => "-p PORT_RULES",
@@ -176,46 +169,37 @@ module KnifeCloudstack
176
169
  :proc => lambda { |o| o.split(/[\s,]+/) },
177
170
  :default => []
178
171
 
179
- option :cloudstack_project,
180
- :short => "-P PROJECT_NAME",
181
- :long => '--cloudstack-project PROJECT_NAME',
182
- :description => "Cloudstack Project in which to create server",
183
- :proc => Proc.new { |v| Chef::Config[:knife][:cloudstack_project] = v },
184
- :default => nil
185
-
186
172
  option :static_nat,
187
- :long => '--static-nat',
188
- :description => 'Support Static NAT',
189
- :boolean => true,
190
- :default => false
191
-
192
- option :use_http_ssl,
193
- :long => '--[no-]use-http-ssl',
194
- :description => 'Support HTTPS',
195
- :boolean => true,
196
- :default => true
197
-
198
- option :bootstrap_protocol,
199
- :long => "--bootstrap-protocol protocol",
200
- :description => "Protocol to bootstrap windows servers. options: winrm/ssh",
201
- :default => "ssh"
173
+ :long => '--static-nat',
174
+ :description => 'Support Static NAT',
175
+ :boolean => true,
176
+ :default => false
202
177
 
203
- option :fqdn,
204
- :long => '--fqdn',
205
- :description => "FQDN which Kerberos Understands (only for Windows Servers)"
178
+ option :ipfwd_rules,
179
+ :long => "--ipfwd-rules PORT_RULES",
180
+ :description => "Comma separated list of ip forwarding rules, e.g. '1024:10000:TCP,1024:2048,22'",
181
+ :proc => lambda { |o| o.split(/[\s,]+/) },
182
+ :default => []
206
183
 
184
+ option :fw_rules,
185
+ :short => "-f PORT_RULES",
186
+ :long => "--fw-rules PORT_RULES",
187
+ :description => "Comma separated list of firewall rules, e.g. '1024:10000:TCP:192.168.0.0/16,25:25:TCP:10.0.0.0/8'",
188
+ :proc => lambda { |o| o.split(/[\s,]+/) },
189
+ :default => []
207
190
 
208
- def connection
209
- @connection ||= CloudstackClient::Connection.new(
210
- locate_config_value(:cloudstack_url),
211
- locate_config_value(:cloudstack_api_key),
212
- locate_config_value(:cloudstack_secret_key),
213
- locate_config_value(:cloudstack_project),
214
- locate_config_value(:use_http_ssl)
215
- )
216
- end
191
+ option :bootstrap_protocol,
192
+ :long => "--bootstrap-protocol protocol",
193
+ :description => "Protocol to bootstrap windows servers. options: winrm/ssh",
194
+ :default => "ssh"
195
+
196
+ option :fqdn,
197
+ :long => '--fqdn',
198
+ :description => "FQDN which Kerberos Understands (only for Windows Servers)"
217
199
 
218
200
  def run
201
+ validate_base_options
202
+
219
203
  Chef::Log.debug("Validate hostname and options")
220
204
  hostname = @name_args.first
221
205
  unless /^[a-zA-Z0-9][a-zA-Z0-9-]*$/.match hostname then
@@ -243,22 +227,33 @@ module KnifeCloudstack
243
227
  network: #{locate_config_value(:cloudstack_networks)}")
244
228
 
245
229
  print "\n#{ui.color("Waiting for Server to be created", :magenta)}"
230
+ params = {}
231
+ params['hypervisor'] = locate_config_value(:cloudstack_hypervisor) if locate_config_value(:cloudstack_hypervisor)
246
232
 
247
233
  server = connection.create_server(
248
234
  hostname,
249
235
  locate_config_value(:cloudstack_service),
250
236
  locate_config_value(:cloudstack_template),
251
237
  locate_config_value(:cloudstack_zone),
252
- locate_config_value(:cloudstack_networks)
238
+ locate_config_value(:cloudstack_networks),
239
+ params
253
240
  )
254
241
 
255
242
  public_ip = find_or_create_public_ip(server, connection)
256
243
 
257
- puts "\n\n"
258
- puts "#{ui.color('Name', :cyan)}: #{server['name']}"
259
- puts "#{ui.color('Public IP', :cyan)}: #{public_ip}"
244
+ object_fields = []
245
+ object_fields << ui.color("Name:", :cyan)
246
+ object_fields << server['name'].to_s
247
+ object_fields << ui.color("Name:", :cyan) if locate_config_value(:cloudstack_password)
248
+ object_fields << server['password'] if locate_config_value(:cloudstack_password)
249
+ object_fields << ui.color("Public IP:", :cyan)
250
+ object_fields << public_ip
251
+
252
+ puts "\n"
253
+ puts ui.list(object_fields, :uneven_columns_across, 2)
254
+ puts "\n"
260
255
 
261
- return if config[:no_bootstrap]
256
+ return unless config[:bootstrap]
262
257
 
263
258
  if @bootstrap_protocol == 'ssh'
264
259
  print "\n#{ui.color("Waiting for sshd", :magenta)}"
@@ -275,11 +270,20 @@ module KnifeCloudstack
275
270
  }
276
271
  end
277
272
 
273
+ object_fields = []
274
+ object_fields << ui.color("Name:", :cyan)
275
+ object_fields << server['name'].to_s
276
+ object_fields << ui.color("Public IP:", :cyan)
277
+ object_fields << public_ip
278
+ object_fields << ui.color("Environment:", :cyan)
279
+ object_fields << (config[:environment] || '_default')
280
+ object_fields << ui.color("Run List:", :cyan)
281
+ object_fields << config[:run_list].join(', ')
282
+
283
+ puts "\n"
284
+ puts ui.list(object_fields, :uneven_columns_across, 2)
278
285
  puts "\n"
279
- puts "#{ui.color("Name", :cyan)}: #{server['name']}"
280
- puts "#{ui.color("Public IP", :cyan)}: #{public_ip}"
281
- puts "#{ui.color("Environment", :cyan)}: #{config[:environment] || '_default'}"
282
- puts "#{ui.color("Run List", :cyan)}: #{config[:run_list].join(', ')}"
286
+
283
287
  bootstrap(server, public_ip).run
284
288
  end
285
289
 
@@ -309,29 +313,31 @@ module KnifeCloudstack
309
313
  ui.error "Cloudstack service offering not specified"
310
314
  exit 1
311
315
  end
312
- if locate_config_value(:bootstrap_protocol) == 'ssh'
313
- identity_file = locate_config_value :identity_file
314
- ssh_user = locate_config_value :ssh_user
315
- ssh_password = locate_config_value :ssh_password
316
- unless identity_file || (ssh_user && ssh_password)
317
- ui.error("You must specify either an ssh identity file or an ssh user and password")
318
- exit 1
319
- end
320
- @bootstrap_protocol = 'ssh'
321
- elsif locate_config_value(:bootstrap_protocol) == 'winrm'
322
- if not @windows_image
323
- ui.error("Only Windows Images support WinRM protocol for bootstrapping.")
324
- exit 1
325
- end
326
- winrm_user = locate_config_value :winrm_user
327
- winrm_password = locate_config_value :winrm_password
328
- winrm_transport = locate_config_value :winrm_transport
329
- winrm_port = locate_config_value :winrm_port
330
- unless winrm_user && winrm_password && winrm_transport && winrm_port
331
- ui.error("WinRM User, Password, Transport and Port are compulsory parameters")
332
- exit 1
316
+ if config[:bootstrap]
317
+ if locate_config_value(:bootstrap_protocol) == 'ssh'
318
+ identity_file = locate_config_value :identity_file
319
+ ssh_user = locate_config_value :ssh_user
320
+ ssh_password = locate_config_value :ssh_password
321
+ unless identity_file || (ssh_user && ssh_password) || locate_config_value(:cloudstack_password)
322
+ ui.error("You must specify either an ssh identity file or an ssh user and password")
323
+ exit 1
324
+ end
325
+ @bootstrap_protocol = 'ssh'
326
+ elsif locate_config_value(:bootstrap_protocol) == 'winrm'
327
+ if not @windows_image
328
+ ui.error("Only Windows Images support WinRM protocol for bootstrapping.")
329
+ exit 1
330
+ end
331
+ winrm_user = locate_config_value :winrm_user
332
+ winrm_password = locate_config_value :winrm_password
333
+ winrm_transport = locate_config_value :winrm_transport
334
+ winrm_port = locate_config_value :winrm_port
335
+ unless (winrm_user && winrm_transport && winrm_port) && (locate_config_value(:cloudstack_password) || winrm_password)
336
+ ui.error("WinRM User, Password, Transport and Port are compulsory parameters")
337
+ exit 1
338
+ end
339
+ @bootstrap_protocol = 'winrm'
333
340
  end
334
- @bootstrap_protocol = 'winrm'
335
341
  end
336
342
  end
337
343
 
@@ -343,7 +349,6 @@ module KnifeCloudstack
343
349
  else
344
350
  puts("\nAllocate ip address, create forwarding rules")
345
351
  ip_address = connection.associate_ip_address(server['zoneid'], locate_config_value(:cloudstack_networks))
346
- #ip_address = connection.get_public_ip_address('202.2.94.158')
347
352
  puts("\nAllocated IP Address: #{ip_address['ipaddress']}")
348
353
  Chef::Log.debug("IP Address Info: #{ip_address}")
349
354
 
@@ -352,21 +357,25 @@ module KnifeCloudstack
352
357
  connection.enable_static_nat(ip_address['id'], server['id'])
353
358
  end
354
359
  create_port_forwarding_rules(ip_address, server['id'], connection)
360
+ create_ip_forwarding_rules(ip_address, connection)
361
+ create_firewall_rules(ip_address, connection)
355
362
  ip_address['ipaddress']
356
363
  end
357
364
  end
358
365
 
359
366
  def create_port_forwarding_rules(ip_address, server_id, connection)
360
367
  rules = locate_config_value(:port_rules)
361
- if @bootstrap_protocol == 'ssh'
362
- rules += ["#{locate_config_value(:ssh_port)}"] #SSH Port
363
- elsif @bootstrap_protocol == 'winrm'
364
- rules +=[locate_config_value(:winrm_port)]
365
- else
366
- puts("\nUnsupported bootstrap protocol : #{@bootstrap_protocol}")
367
- exit 1
368
+ if config[:bootstrap]
369
+ if @bootstrap_protocol == 'ssh'
370
+ rules += ["#{locate_config_value(:ssh_port)}"] #SSH Port
371
+ elsif @bootstrap_protocol == 'winrm'
372
+ rules +=[locate_config_value(:winrm_port)]
373
+ else
374
+ puts("\nUnsupported bootstrap protocol : #{@bootstrap_protocol}")
375
+ exit 1
376
+ end
368
377
  end
369
- return unless rules
378
+ return unless rules
370
379
  rules.each do |rule|
371
380
  args = rule.split(':')
372
381
  public_port = args[0]
@@ -384,6 +393,37 @@ module KnifeCloudstack
384
393
  end
385
394
  end
386
395
 
396
+ def create_ip_forwarding_rules(ip_address, connection)
397
+ rules = locate_config_value(:ipfwd_rules)
398
+ return unless rules
399
+ rules.each do |rule|
400
+ args = rule.split(':')
401
+ startport = args[0]
402
+ endport = args[1] || args[0]
403
+ protocol = args[2] || "TCP"
404
+ if locate_config_value :static_nat
405
+ Chef::Log.debug("Creating IP Forwarding Rule for
406
+ #{ip_address['ipaddress']} with protocol: #{protocol}, startport: #{startport}, endport: #{endport}")
407
+ connection.create_ip_fwd_rule(ip_address['id'], protocol, startport, endport)
408
+ end
409
+ end
410
+ end
411
+
412
+ def create_firewall_rules(ip_address, connection)
413
+ rules = locate_config_value(:fw_rules)
414
+ return unless rules
415
+ rules.each do |rule|
416
+ args = rule.split(':')
417
+ startport = args[0]
418
+ endport = args[1] || args[0]
419
+ protocol = args[2] || "TCP"
420
+ cidr_list = args[3] || "0.0.0.0/0"
421
+ Chef::Log.debug("Creating Firewall Rule for
422
+ #{ip_address['ipaddress']} with protocol: #{protocol}, startport: #{startport}, endport: #{endport}, cidrList: #{cidr_list}")
423
+ connection.create_firewall_rule(ip_address['id'], protocol, startport, endport, cidr_list)
424
+ end
425
+ end
426
+
387
427
  def tcp_test_winrm(hostname, port)
388
428
  TCPSocket.new(hostname, port)
389
429
  return true
@@ -433,6 +473,7 @@ module KnifeCloudstack
433
473
  s && s.close
434
474
  end
435
475
  end
476
+
436
477
  def is_platform_windows?
437
478
  return RUBY_PLATFORM.scan('w32').size > 0
438
479
  end
@@ -446,38 +487,43 @@ module KnifeCloudstack
446
487
  bootstrap_for_node(server, public_ip)
447
488
  end
448
489
  end
490
+
449
491
  def bootstrap_for_windows_node(server, fqdn)
450
- if locate_config_value(:bootstrap_protocol) == 'winrm'
451
- bootstrap = Chef::Knife::BootstrapWindowsWinrm.new
452
- if locate_config_value(:kerberos_realm)
453
- #Fetch AD/WINS based fqdn if any for Kerberos-based Auth
454
- private_ip_address = connection.get_server_default_nic(server)["ipaddress"]
455
- fqdn = locate_config_value(:fqdn) || fetch_server_fqdn(private_ip_address)
456
- end
457
- bootstrap.name_args = [fqdn]
458
- bootstrap.config[:winrm_user] = locate_config_value(:winrm_user) || 'Administrator'
459
- bootstrap.config[:winrm_password] = locate_config_value(:winrm_password)
460
- bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport)
461
- bootstrap.config[:winrm_port] = locate_config_value(:winrm_port)
462
-
463
- elsif locate_config_value(:bootstrap_protocol) == 'ssh'
464
- bootstrap = Chef::Knife::BootstrapWindowsSsh.new
465
- bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
466
- bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
467
- bootstrap.config[:ssh_port] = locate_config_value(:ssh_port)
468
- bootstrap.config[:identity_file] = locate_config_value(:identity_file)
469
- bootstrap.config[:no_host_key_verify] = locate_config_value(:no_host_key_verify)
492
+ if locate_config_value(:bootstrap_protocol) == 'winrm'
493
+ bootstrap = Chef::Knife::BootstrapWindowsWinrm.new
494
+ if locate_config_value(:kerberos_realm)
495
+ #Fetch AD/WINS based fqdn if any for Kerberos-based Auth
496
+ private_ip_address = connection.get_server_default_nic(server)["ipaddress"]
497
+ fqdn = locate_config_value(:fqdn) || fetch_server_fqdn(private_ip_address)
498
+ end
499
+ bootstrap.name_args = [fqdn]
500
+ bootstrap.config[:winrm_user] = locate_config_value(:winrm_user) || 'Administrator'
501
+ locate_config_value(:cloudstack_password) ? bootstrap.config[:winrm_password] = server['password'] : bootstrap.config[:winrm_password] = locate_config_value(:winrm_password)
502
+ bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport)
503
+ bootstrap.config[:winrm_port] = locate_config_value(:winrm_port)
504
+ elsif locate_config_value(:bootstrap_protocol) == 'ssh'
505
+ bootstrap = Chef::Knife::BootstrapWindowsSsh.new
506
+ if locate_config_value(:cloudstack_password)
507
+ bootstrap.config[:ssh_user] = locate_config_value(:ssh_user) || 'Administrator'
470
508
  else
471
- ui.error("Unsupported Bootstrapping Protocol. Supported : winrm, ssh")
472
- exit 1
509
+ bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
473
510
  end
474
- bootstrap.config[:chef_node_name] = config[:chef_node_name] || server['id']
475
- bootstrap.config[:encrypted_data_bag_secret] = config[:encrypted_data_bag_secret]
476
- bootstrap.config[:encrypted_data_bag_secret_file] = config[:encrypted_data_bag_secret_file]
477
- bootstrap_common_params(bootstrap)
511
+ locate_config_value(:cloudstack_password) ? bootstrap.config[:ssh_password] = server['password'] : bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
512
+ bootstrap.config[:ssh_port] = locate_config_value(:ssh_port)
513
+ bootstrap.config[:identity_file] = locate_config_value(:identity_file)
514
+ bootstrap.config[:no_host_key_verify] = locate_config_value(:no_host_key_verify)
515
+ else
516
+ ui.error("Unsupported Bootstrapping Protocol. Supported : winrm, ssh")
517
+ exit 1
518
+ end
519
+ bootstrap.config[:environment] = locate_config_value(:environment)
520
+ bootstrap.config[:chef_node_name] = config[:chef_node_name] || server['id']
521
+ bootstrap.config[:encrypted_data_bag_secret] = config[:encrypted_data_bag_secret]
522
+ bootstrap.config[:encrypted_data_bag_secret_file] = config[:encrypted_data_bag_secret_file]
523
+ bootstrap_common_params(bootstrap)
478
524
  end
479
- def bootstrap_common_params(bootstrap)
480
525
 
526
+ def bootstrap_common_params(bootstrap)
481
527
  bootstrap.config[:run_list] = config[:run_list]
482
528
  bootstrap.config[:prerelease] = config[:prerelease]
483
529
  bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
@@ -486,30 +532,25 @@ module KnifeCloudstack
486
532
  bootstrap
487
533
  end
488
534
 
489
-
490
535
  def bootstrap_for_node(server,fqdn)
491
536
  bootstrap = Chef::Knife::Bootstrap.new
492
537
  bootstrap.name_args = [fqdn]
493
- # bootstrap.config[:run_list] = config[:run_list]
494
- bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
495
- bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
538
+ if locate_config_value(:cloudstack_password)
539
+ bootstrap.config[:ssh_user] = locate_config_value(:ssh_user) || 'root'
540
+ else
541
+ bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
542
+ end
543
+ locate_config_value(:cloudstack_password) ? bootstrap.config[:ssh_password] = server['password'] : bootstrap.config[:ssh_password] = locate_config_value(:ssh_password)
496
544
  bootstrap.config[:ssh_port] = locate_config_value(:ssh_port) || 22
497
545
  bootstrap.config[:identity_file] = locate_config_value(:identity_file)
498
- bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server.name
499
- # bootstrap.config[:prerelease] = locate_config_value(:prerelease)
500
- # bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
501
- # bootstrap.config[:distro] = locate_config_value(:distro)
546
+ bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server["name"]
502
547
  bootstrap.config[:use_sudo] = true unless locate_config_value(:ssh_user) == 'root'
503
- # bootstrap.config[:template_file] = config[:template_file]
504
548
  bootstrap.config[:environment] = locate_config_value(:environment)
549
+
505
550
  # may be needed for vpc_mode
506
551
  bootstrap.config[:host_key_verify] = config[:host_key_verify]
507
552
  bootstrap_common_params(bootstrap)
508
553
  end
509
554
 
510
- def locate_config_value(key)
511
- key = key.to_sym
512
- Chef::Config[:knife][key] || config[key]
513
- end
514
555
  end
515
556
  end