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.
- data/CHANGES.rdoc +50 -0
- data/README.rdoc +221 -42
- data/lib/chef/knife/cs_account_list.rb +130 -0
- data/lib/chef/knife/cs_base.rb +98 -0
- data/lib/chef/knife/cs_baselist.rb +81 -0
- data/lib/chef/knife/cs_cluster_list.rb +93 -0
- data/lib/chef/knife/cs_config_list.rb +85 -0
- data/lib/chef/knife/cs_disk_list.rb +89 -0
- data/lib/chef/knife/cs_domain_list.rb +83 -0
- data/lib/chef/knife/cs_firewallrule_list.rb +95 -0
- data/lib/chef/knife/cs_host_list.rb +95 -0
- data/lib/chef/knife/cs_hosts.rb +2 -2
- data/lib/chef/knife/cs_iso_list.rb +103 -0
- data/lib/chef/knife/cs_network_list.rb +56 -46
- data/lib/chef/knife/cs_oscategory_list.rb +78 -0
- data/lib/chef/knife/cs_ostype_list.rb +80 -0
- data/lib/chef/knife/cs_pod_list.rb +93 -0
- data/lib/chef/knife/cs_project_list.rb +92 -0
- data/lib/chef/knife/cs_router_list.rb +94 -0
- data/lib/chef/knife/cs_server_create.rb +185 -144
- data/lib/chef/knife/cs_server_delete.rb +62 -79
- data/lib/chef/knife/cs_server_list.rb +136 -57
- data/lib/chef/knife/cs_server_reboot.rb +50 -54
- data/lib/chef/knife/cs_server_start.rb +48 -52
- data/lib/chef/knife/cs_server_stop.rb +54 -55
- data/lib/chef/knife/cs_service_list.rb +62 -41
- data/lib/chef/knife/cs_stack_create.rb +2 -2
- data/lib/chef/knife/cs_stack_delete.rb +2 -2
- data/lib/chef/knife/cs_template_create.rb +121 -0
- data/lib/chef/knife/cs_template_extract.rb +104 -0
- data/lib/chef/knife/cs_template_list.rb +65 -63
- data/lib/chef/knife/cs_template_register.rb +180 -0
- data/lib/chef/knife/cs_user_list.rb +93 -0
- data/lib/chef/knife/cs_volume_list.rb +94 -0
- data/lib/chef/knife/cs_zone_list.rb +55 -36
- data/lib/knife-cloudstack/connection.rb +75 -22
- data/lib/knife-cloudstack/string_to_regexp.rb +32 -0
- 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 => "
|
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 :
|
167
|
-
:long => "--no-bootstrap",
|
159
|
+
option :bootstrap,
|
160
|
+
:long => "--[no-]bootstrap",
|
168
161
|
:description => "Disable Chef bootstrap",
|
169
162
|
:boolean => true,
|
170
|
-
:default =>
|
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
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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 :
|
204
|
-
|
205
|
-
|
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
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
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
|
-
|
258
|
-
|
259
|
-
|
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
|
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
|
-
|
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
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
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
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
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
|
-
|
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
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
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
|
-
|
472
|
-
exit 1
|
509
|
+
bootstrap.config[:ssh_user] = locate_config_value(:ssh_user)
|
473
510
|
end
|
474
|
-
bootstrap.config[:
|
475
|
-
bootstrap.config[:
|
476
|
-
bootstrap.config[:
|
477
|
-
|
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
|
-
|
494
|
-
|
495
|
-
|
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
|
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
|