knife-cosmic 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.rdoc +186 -0
  3. data/LICENSE +202 -0
  4. data/README.rdoc +427 -0
  5. data/lib/chef/knife/cosmic_aag_list.rb +58 -0
  6. data/lib/chef/knife/cosmic_account_list.rb +87 -0
  7. data/lib/chef/knife/cosmic_base.rb +108 -0
  8. data/lib/chef/knife/cosmic_baselist.rb +111 -0
  9. data/lib/chef/knife/cosmic_cluster_list.rb +60 -0
  10. data/lib/chef/knife/cosmic_config_list.rb +56 -0
  11. data/lib/chef/knife/cosmic_disk_list.rb +58 -0
  12. data/lib/chef/knife/cosmic_domain_list.rb +53 -0
  13. data/lib/chef/knife/cosmic_firewallrule_create.rb +138 -0
  14. data/lib/chef/knife/cosmic_firewallrule_list.rb +62 -0
  15. data/lib/chef/knife/cosmic_forwardrule_create.rb +145 -0
  16. data/lib/chef/knife/cosmic_host_list.rb +61 -0
  17. data/lib/chef/knife/cosmic_hosts.rb +58 -0
  18. data/lib/chef/knife/cosmic_iso_list.rb +89 -0
  19. data/lib/chef/knife/cosmic_keypair_create.rb +72 -0
  20. data/lib/chef/knife/cosmic_keypair_delete.rb +60 -0
  21. data/lib/chef/knife/cosmic_keypair_list.rb +44 -0
  22. data/lib/chef/knife/cosmic_network_list.rb +63 -0
  23. data/lib/chef/knife/cosmic_oscategory_list.rb +50 -0
  24. data/lib/chef/knife/cosmic_ostype_list.rb +52 -0
  25. data/lib/chef/knife/cosmic_pod_list.rb +60 -0
  26. data/lib/chef/knife/cosmic_project_list.rb +63 -0
  27. data/lib/chef/knife/cosmic_publicip_list.rb +55 -0
  28. data/lib/chef/knife/cosmic_router_list.rb +64 -0
  29. data/lib/chef/knife/cosmic_securitygroup_list.rb +59 -0
  30. data/lib/chef/knife/cosmic_server_add_nic.rb +109 -0
  31. data/lib/chef/knife/cosmic_server_create.rb +674 -0
  32. data/lib/chef/knife/cosmic_server_delete.rb +153 -0
  33. data/lib/chef/knife/cosmic_server_list.rb +167 -0
  34. data/lib/chef/knife/cosmic_server_passwordreset.rb +91 -0
  35. data/lib/chef/knife/cosmic_server_reboot.rb +99 -0
  36. data/lib/chef/knife/cosmic_server_remove_nic.rb +101 -0
  37. data/lib/chef/knife/cosmic_server_start.rb +104 -0
  38. data/lib/chef/knife/cosmic_server_stop.rb +118 -0
  39. data/lib/chef/knife/cosmic_server_update.rb +47 -0
  40. data/lib/chef/knife/cosmic_service_list.rb +74 -0
  41. data/lib/chef/knife/cosmic_stack_create.rb +298 -0
  42. data/lib/chef/knife/cosmic_stack_delete.rb +79 -0
  43. data/lib/chef/knife/cosmic_template_create.rb +129 -0
  44. data/lib/chef/knife/cosmic_template_extract.rb +104 -0
  45. data/lib/chef/knife/cosmic_template_list.rb +88 -0
  46. data/lib/chef/knife/cosmic_template_register.rb +187 -0
  47. data/lib/chef/knife/cosmic_user_list.rb +62 -0
  48. data/lib/chef/knife/cosmic_volume_attach.rb +70 -0
  49. data/lib/chef/knife/cosmic_volume_create.rb +108 -0
  50. data/lib/chef/knife/cosmic_volume_delete.rb +97 -0
  51. data/lib/chef/knife/cosmic_volume_detach.rb +61 -0
  52. data/lib/chef/knife/cosmic_volume_list.rb +77 -0
  53. data/lib/chef/knife/cosmic_zone_list.rb +53 -0
  54. data/lib/knife-cosmic/connection.rb +1046 -0
  55. metadata +127 -0
@@ -0,0 +1,101 @@
1
+ #
2
+ # Original knife-cloudstack author:: John E. Vincent (<lusis.org+github.com@gmail.com>)
3
+ # Copyright:: Copyright (c) 2013 John E. Vincent
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
+ require 'chef/knife/cosmic_base'
19
+ require 'chef/knife/cosmic_baselist'
20
+
21
+ module Knifecosmic
22
+ class CosmicServerRemoveNic < Chef::Knife
23
+
24
+ include Chef::Knife::KnifecosmicBase
25
+ include Chef::Knife::KnifecosmicBaseList
26
+
27
+ deps do
28
+ require 'knife-cosmic/connection'
29
+ require 'chef/knife'
30
+ Chef::Knife.load_deps
31
+ end
32
+
33
+ banner "knife cosmic server remove nic SERVERID NICID"
34
+
35
+
36
+ def run
37
+ validate_base_options
38
+
39
+ @server_id, @nic_id = name_args
40
+
41
+ if @server_id.nil? || @nic_id.nil?
42
+ show_usage
43
+ ui.fatal("You must provide both a nic id and a server id")
44
+ exit(1)
45
+ end
46
+
47
+
48
+ object_list = []
49
+ if locate_config_value(:fields)
50
+ locate_config_value(:fields).split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
51
+ else
52
+ object_list << ui.color('Server', :bold)
53
+ object_list << ui.color('Network', :bold)
54
+ object_list << ui.color('Type', :bold)
55
+ object_list << ui.color('Default', :bold)
56
+ object_list << ui.color('Address', :bold)
57
+ object_list << ui.color('Gateway', :bold)
58
+ object_list << ui.color('Netmask', :bold)
59
+ object_list << ui.color('ID', :bold)
60
+ end
61
+
62
+ columns = object_list.count
63
+
64
+ connection_result = connection.remove_nic_from_vm(
65
+ @nic_id,
66
+ @server_id
67
+ )
68
+
69
+ output_format(connection_result)
70
+
71
+ object_list << connection_result['name']
72
+ object_list << ''
73
+ object_list << ''
74
+ object_list << ''
75
+ object_list << ''
76
+ object_list << ''
77
+ object_list << ''
78
+ object_list << ''
79
+ if connection_result['nic']
80
+ connection_result['nic'].each do |r|
81
+ if locate_config_value(:fields)
82
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
83
+ else
84
+ object_list << ''
85
+ object_list << r['networkname'].to_s
86
+ object_list << r['type'].to_s
87
+ object_list << (r['isdefault'] ? r['isdefault'].to_s : 'false')
88
+ object_list << (r['ipaddress'] || '')
89
+ object_list << (r['gateway'] || '')
90
+ object_list << (r['netmask'] || '')
91
+ object_list << (r['networkid'] || '')
92
+ end
93
+ end
94
+ puts ui.list(object_list, :uneven_columns_across, columns)
95
+ list_object_fields(connection_result) if locate_config_value(:fieldlist)
96
+ else
97
+ ui.error("No nicosmic returned in response")
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,104 @@
1
+ #
2
+ # Original knife-cloudstack author:: Ryan Holmes (<rholmes@edmunds.com>)
3
+ # Original knife-cloudstack author:: KC Braunschweig (<kcbraunschweig@gmail.com>)
4
+ # Original knife-cloudstack author:: Sander Botman (<sbotman@schubergphilis.com>)
5
+ # Copyright:: Copyright (c) 2011 Edmunds, Inc.
6
+ # Copyright:: Copyright (c) 2013 Sander Botman.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+
22
+ require 'chef/knife/cosmic_base'
23
+
24
+ module Knifecosmic
25
+ class CosmicServerStart < Chef::Knife
26
+
27
+ include Chef::Knife::KnifecosmicBase
28
+
29
+ deps do
30
+ require 'chef/knife'
31
+ require 'knife-cosmic/connection'
32
+ require 'chef/api_client'
33
+ Chef::Knife.load_deps
34
+ end
35
+
36
+ banner "knife cosmic server start SERVER_NAME [SERVER_NAME ...] (options)"
37
+
38
+ option :confirm,
39
+ :long => "--confirm",
40
+ :description => "Dont ask for confirmation.",
41
+ :boolean => true
42
+
43
+ def run
44
+ validate_base_options
45
+
46
+ @name_args.each do |hostname|
47
+ server = connection.get_server(hostname)
48
+
49
+ if !server then
50
+ ui.error("Server '#{hostname}' not found")
51
+ next
52
+ end
53
+
54
+ rules = connection.list_port_forwarding_rules
55
+
56
+ show_object_details(server, connection, rules)
57
+
58
+ result = config[:confirm] ? true : confirm_action("Do you really want to start this server")
59
+ if result
60
+ print "#{ui.color("Waiting for startup", :magenta)}"
61
+ connection.start_server(hostname)
62
+ puts "\n"
63
+ ui.msg("Started server #{hostname}")
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ def show_object_details(s, connection, rules)
70
+ return if locate_config_value(:yes)
71
+
72
+ object_fields = []
73
+ object_fields << ui.color("Name:", :cyan)
74
+ object_fields << s['name'].to_s
75
+ object_fields << ui.color("Public IP:", :cyan)
76
+ object_fields << (connection.get_server_public_ip(s, rules) || '')
77
+ object_fields << ui.color("Service:", :cyan)
78
+ object_fields << s['serviceofferingname'].to_s
79
+ object_fields << ui.color("Template:", :cyan)
80
+ object_fields << s['templatename']
81
+ object_fields << ui.color("Domain:", :cyan)
82
+ object_fields << s['domain']
83
+ object_fields << ui.color("Zone:", :cyan)
84
+ object_fields << s['zonename']
85
+ object_fields << ui.color("State:", :cyan)
86
+ object_fields << s['state']
87
+
88
+ puts "\n"
89
+ puts ui.list(object_fields, :uneven_columns_across, 2)
90
+ puts "\n"
91
+ end
92
+
93
+ def confirm_action(question)
94
+ return true if locate_config_value(:yes)
95
+ result = ui.ask_question(question, :default => "Y" )
96
+ if result == "Y" || result == "y" then
97
+ return true
98
+ else
99
+ return false
100
+ end
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,118 @@
1
+ #
2
+ # Original knife-cloudstack author:: Ryan Holmes (<rholmes@edmunds.com>)
3
+ # Original knife-cloudstack author:: KC Braunschweig (<kcbraunschweig@gmail.com>)
4
+ # Original knife-cloudstack author:: Sander Botman (<sbotman@schubergphilis.com>)
5
+ # Copyright:: Copyright (c) 2011 Edmunds, Inc.
6
+ # Copyright:: Copyright (c) 2013 Sander Botman.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+
22
+ require 'chef/knife/cosmic_base'
23
+
24
+ module Knifecosmic
25
+ class CosmicServerStop < Chef::Knife
26
+
27
+ include Chef::Knife::KnifecosmicBase
28
+
29
+ deps do
30
+ require 'knife-cosmic/connection'
31
+ require 'chef/api_client'
32
+ require 'chef/knife'
33
+ Chef::Knife.load_deps
34
+ end
35
+
36
+ banner "knife cosmic server stop SERVER_NAME [SERVER_NAME ...] (options)"
37
+
38
+ option :cosmic_force_stop,
39
+ :long => "--force",
40
+ :description => "Force stop the VM. The caller knows the VM is stopped.",
41
+ :boolean => true
42
+
43
+ option :confirm,
44
+ :long => "--confirm",
45
+ :description => "Dont ask for confirmation.",
46
+ :boolean => true
47
+
48
+ def run
49
+ validate_base_options
50
+
51
+ @name_args.each do |hostname|
52
+ server = connection.get_server(hostname)
53
+
54
+ if !server then
55
+ ui.error("Server '#{hostname}' not found")
56
+ next
57
+ end
58
+
59
+ rules = connection.list_port_forwarding_rules
60
+
61
+ show_object_details(server, connection, rules)
62
+
63
+ if config[:cosmic_force_stop]
64
+ result = config[:confirm] ? true : confirm_action("Do you really want to force stop this server")
65
+ if result
66
+ print "#{ui.color("Forcefully stopping", :magenta)}"
67
+ connection.stop_server(hostname,config[:cosmic_force_stop])
68
+ puts "\n"
69
+ ui.msg("Stopped server #{hostname}")
70
+ end
71
+ else
72
+ result = config[:confirm] ? true : confirm_action("Do you really want to stop this server")
73
+ if result
74
+ print "#{ui.color("Stopping", :magenta)}"
75
+ connection.stop_server(hostname)
76
+ puts "\n"
77
+ ui.msg("Stopped server #{hostname}")
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def show_object_details(s, connection, rules)
84
+ return if locate_config_value(:yes)
85
+
86
+ object_fields = []
87
+ object_fields << ui.color("Name:", :cyan)
88
+ object_fields << s['name'].to_s
89
+ object_fields << ui.color("Public IP:", :cyan)
90
+ object_fields << (connection.get_server_public_ip(s, rules) || '')
91
+ object_fields << ui.color("Service:", :cyan)
92
+ object_fields << s['serviceofferingname'].to_s
93
+ object_fields << ui.color("Template:", :cyan)
94
+ object_fields << s['templatename']
95
+ object_fields << ui.color("Domain:", :cyan)
96
+ object_fields << s['domain']
97
+ object_fields << ui.color("Zone:", :cyan)
98
+ object_fields << s['zonename']
99
+ object_fields << ui.color("State:", :cyan)
100
+ object_fields << s['state']
101
+
102
+ puts "\n"
103
+ puts ui.list(object_fields, :uneven_columns_across, 2)
104
+ puts "\n"
105
+ end
106
+
107
+ def confirm_action(question)
108
+ return true if locate_config_value(:yes)
109
+ result = ui.ask_question(question, :default => "Y" )
110
+ if result == "Y" || result == "y" then
111
+ return true
112
+ else
113
+ return false
114
+ end
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,47 @@
1
+ #
2
+ # knife-cosmic author:: Robbert-Jan Sperna Weiland (<rspernaweiland@schubergphilis.com>)
3
+ # Copyright:: Copyright (c) 2018 Robbert-Jan Sperna Weiland.
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/cosmic_base'
20
+ require 'chef/knife/winrm_base'
21
+
22
+ module Knifecosmic
23
+ class CosmicServerUpdate < Chef::Knife
24
+
25
+ include Chef::Knife::KnifecosmicBase
26
+
27
+ deps do
28
+ require 'chef/knife'
29
+ require 'chef/json_compat'
30
+ require 'knife-cosmic/connection'
31
+ require 'httpclient'
32
+ end
33
+
34
+ banner "knife cosmic server update [SERVER_NAME] (options)"
35
+
36
+ def run
37
+ validate_base_options
38
+
39
+ params = {}
40
+ for key in config.keys
41
+ params["#{key}"] = config[:"#{key}"]
42
+ end
43
+ @server = connection.server_update(params)
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,74 @@
1
+ #
2
+ # Original knife-cloudstack author:: Ryan Holmes (<rholmes@edmunds.com>)
3
+ # Original knife-cloudstack author:: Sander Botman (<sbotman@schubergphilis.com>)
4
+ # Copyright:: Copyright (c) 2011 Edmunds, Inc.
5
+ # Copyright:: Copyright (c) 2013 Sander Botman.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ require 'chef/knife'
22
+ require 'chef/knife/cosmic_baselist'
23
+
24
+ module Knifecosmic
25
+ class CosmicServiceList < Chef::Knife
26
+
27
+ include Chef::Knife::KnifecosmicBaseList
28
+
29
+ banner "knife cosmic service list (options)"
30
+
31
+ option :name,
32
+ :long => "--name NAME",
33
+ :description => "Specify servicename to list"
34
+
35
+ option :keyword,
36
+ :long => "--keyword NAME",
37
+ :description => "Specify part of servicename to list"
38
+
39
+ def run
40
+ validate_base_options
41
+
42
+ columns = [
43
+ 'Name :name',
44
+ 'Memory :memory',
45
+ 'CPUs :cpunumber',
46
+ 'CPU Speed :cpuspeed',
47
+ 'Created :created'
48
+ ]
49
+
50
+ params = { 'command' => "listServiceOfferings" }
51
+ params['filter'] = locate_config_value(:filter) if locate_config_value(:filter)
52
+ params['keyword'] = locate_config_value(:keyword) if locate_config_value(:keyword)
53
+ params['name'] = locate_config_value(:name) if locate_config_value(:name)
54
+
55
+ result = connection.list_object(params, "serviceoffering")
56
+
57
+ result.each do |r|
58
+ r['memory'] = human_memory(r['memory']) if r['memory']
59
+ end
60
+
61
+ list_object(columns, result)
62
+ end
63
+
64
+ def human_memory n
65
+ count = 0
66
+ while n >= 1024 and count < 2
67
+ n /= 1024.0
68
+ count += 1
69
+ end
70
+ format("%.0f", n) + %w(MB GB TB)[count]
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,298 @@
1
+ #
2
+ # Original knife-cloudstack author:: Ryan Holmes (<rholmes@edmunds.com>)
3
+ # Copyright:: Copyright (c) 2011 Edmunds, Inc.
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/cosmic_base'
20
+ require 'chef/knife/cosmic_baselist'
21
+
22
+ module Knifecosmic
23
+ class CosmicStackCreate < Chef::Knife
24
+
25
+ attr_accessor :current_stack
26
+
27
+ include Chef::Knife::KnifecosmicBase
28
+ include Chef::Knife::KnifecosmicBaseList
29
+
30
+ deps do
31
+ require 'chef/json_compat'
32
+ require 'chef/mash'
33
+ require 'chef/search/query'
34
+ require 'chef/knife/node_run_list_remove'
35
+ require 'net/ssh'
36
+ require 'net/ssh/multi'
37
+ require 'knife-cosmic/connection'
38
+ Chef::Knife.load_deps
39
+ Chef::Knife::Ssh.load_deps
40
+ Chef::Knife::NodeRunListRemove.load_deps
41
+ Knifecosmic::CosmicServerCreate.load_deps
42
+ end
43
+
44
+ banner "knife cosmic stack create JSON_FILE (options)"
45
+
46
+ option :ssh_user,
47
+ :short => "-x USERNAME",
48
+ :long => "--ssh-user USERNAME",
49
+ :description => "The ssh username"
50
+
51
+ option :ssh_password,
52
+ :short => "-P PASSWORD",
53
+ :long => "--ssh-password PASSWORD",
54
+ :description => "The ssh password"
55
+
56
+ option :identity_file,
57
+ :short => "-i IDENTITY_FILE",
58
+ :long => "--identity-file IDENTITY_FILE",
59
+ :description => "The SSH identity file used for authentication"
60
+
61
+ option :skip_existing,
62
+ :long => "--skip-existing",
63
+ :default => false,
64
+ :description => "Skip creating existing server(s)"
65
+
66
+ def run
67
+ validate_base_options
68
+ if @name_args.first.nil?
69
+ ui.error "Please specify json file eg: knife cosmic stack create JSON_FILE"
70
+ exit 1
71
+ end
72
+ file_path = File.expand_path(@name_args.first)
73
+ unless File.exist?(file_path) then
74
+ ui.error "Stack file '#{file_path}' not found. Please check the path."
75
+ exit 1
76
+ end
77
+
78
+ data = File.read file_path
79
+ stack = Chef::JSONCompat.from_json data
80
+ create_stack stack
81
+ end
82
+
83
+ def create_stack(stack)
84
+ @current_stack = Mash.new(stack)
85
+ current_stack[:servers].each do |server|
86
+ if server[:name]
87
+ # create server(s)
88
+ names = server[:name].split(/[\s,]+/)
89
+ names.each do |n|
90
+ if (config[:skip_existing] && connection.get_server(n))
91
+ ui.msg(ui.color("\nServer #{n} already exists; skipping create...", :yellow))
92
+ else
93
+ s = Mash.new(server)
94
+ s[:name] = n
95
+ create_server(s)
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ # execute actions
102
+ run_actions server[:actions]
103
+ end
104
+
105
+ print_local_hosts
106
+ end
107
+
108
+ def create_server(server)
109
+
110
+ cmd = Knifecosmic::CosmicServerCreate.new([server[:name]])
111
+ # configure and run command
112
+ # TODO: validate parameters
113
+ cmd.config[:cosmic_url] = config[:cosmic_url]
114
+ cmd.config[:cosmic_api_key] = config[:cosmic_api_key]
115
+ cmd.config[:cosmic_secret_key] = config[:cosmic_secret_key]
116
+ cmd.config[:cosmic_proxy] = config[:cosmic_proxy]
117
+ cmd.config[:cosmic_no_ssl_verify] = config[:cosmic_no_ssl_verify]
118
+ cmd.config[:cosmic_project] = config[:cosmic_project]
119
+ cmd.config[:ssh_user] = config[:ssh_user]
120
+ cmd.config[:ssh_password] = config[:ssh_password]
121
+ cmd.config[:ssh_port] = server[:ssh_port] || locate_config_value(:ssh_port) || "22"
122
+ cmd.config[:identity_file] = config[:identity_file]
123
+ cmd.config[:keypair] = server[:keypair]
124
+ cmd.config[:cosmic_template] = server[:template] if server[:template]
125
+ cmd.config[:cosmic_service] = server[:service] if server[:service]
126
+ cmd.config[:cosmic_zone] = server[:zone] if server[:zone]
127
+ server.has_key?(:public_ip) ? cmd.config[:public_ip] = server[:public_ip] : cmd.config[:no_public_ip] = true
128
+ cmd.config[:ik_private_ip] = server[:private_ip] if server[:private_ip]
129
+ cmd.config[:bootstrap] = server[:bootstrap] if server.has_key?(:bootstrap)
130
+ cmd.config[:bootstrap_protocol] = server[:bootstrap_protocol] || "ssh"
131
+ cmd.config[:distro] = server[:distro] || "chef-full"
132
+ cmd.config[:template_file] = server[:template_file] if server.has_key?(:template_file)
133
+ cmd.config[:no_host_key_verify] = server[:no_host_key_verify] if server.has_key?(:no_host_key_verify)
134
+ cmd.config[:cosmic_networks] = server[:networks].split(/[\s,]+/) if server[:networks]
135
+ cmd.config[:run_list] = server[:run_list].split(/[\s,]+/) if server[:run_list]
136
+ cmd.config[:port_rules] = server[:port_rules].split(/[\s,]+/) if server[:port_rules]
137
+ if current_stack[:environment]
138
+ cmd.config[:environment] = current_stack[:environment]
139
+ Chef::Config[:environment] = current_stack[:environment]
140
+ end
141
+
142
+ cmd.run_with_pretty_exceptions
143
+ end
144
+
145
+ def run_actions(actions)
146
+ return if actions.nil? || actions.empty?
147
+ puts "\n"
148
+ ui.msg("Processing actions...")
149
+ sleep 1 # pause for e.g. chef solr indexing
150
+ actions ||= []
151
+ actions.each do |cmd|
152
+ cmd ||= {}
153
+ cmd.each do |name, args|
154
+ case name
155
+ when 'knife_ssh'
156
+ knife_ssh_action(*args)
157
+ when 'http_request'
158
+ http_request(args)
159
+ when 'run_list_remove'
160
+ run_list_remove(*args)
161
+ when 'sleep'
162
+ dur = args || 5
163
+ sleep dur
164
+ end
165
+ end
166
+ end
167
+
168
+ end
169
+
170
+ def search_nodes(query, attribute=nil)
171
+ if get_environment
172
+ query = "(#{query})" + " AND chef_environment:#{get_environment}"
173
+ end
174
+
175
+ Chef::Log.debug("Searching for nodes: #{query}")
176
+
177
+ q = Chef::Search::Query.new
178
+ nodes = Array(q.search(:node, query))
179
+
180
+ # the array of nodes is the first item in the array returned by the search
181
+ if nodes.length > 1
182
+ nodes = nodes.first || []
183
+ end
184
+
185
+ # return attribute values instead of nodes
186
+ if attribute
187
+ nodes.map do |node|
188
+ node[attribute.to_s]
189
+ end
190
+ else
191
+ nodes
192
+ end
193
+ end
194
+
195
+ def knife_ssh(host_list, command)
196
+ ssh = Chef::Knife::Ssh.new
197
+ ssh.name_args = [host_list, command]
198
+ ssh.config[:ssh_user] = config[:ssh_user]
199
+ ssh.config[:ssh_password] = config[:ssh_password]
200
+ ssh.config[:ssh_port] = Chef::Config[:knife][:ssh_port] || config[:ssh_port]
201
+ ssh.config[:identity_file] = config[:identity_file]
202
+ ssh.config[:manual] = true
203
+ ssh.config[:no_host_key_verify] = config[:no_host_key_verify]
204
+ ssh
205
+ end
206
+
207
+ def knife_ssh_with_password_auth(host_list, command)
208
+ ssh = knife_ssh(host_list, command)
209
+ ssh.config[:identity_file] = nil
210
+ ssh.config[:ssh_password] = ssh.get_password
211
+ ssh
212
+ end
213
+
214
+ def knife_ssh_action(query, command)
215
+ public_ips = find_public_ips(query)
216
+ return if public_ips.nil? || public_ips.empty?
217
+ host_list = public_ips.join(' ')
218
+
219
+ ssh = knife_ssh(host_list, command)
220
+ begin
221
+ ssh.run
222
+ rescue Net::SSH::AuthenticationFailed
223
+ unless config[:ssh_password]
224
+ puts "Failed to authenticate #{config[:ssh_user]} - trying password auth"
225
+ ssh = knife_ssh_with_password_auth(host_list, command)
226
+ ssh.run
227
+ end
228
+ end
229
+ end
230
+
231
+ def http_request(url)
232
+ match_data = /\$\{([a-zA-Z0-9-]+)\}/.match url
233
+ if match_data
234
+ server_name = match_data[1]
235
+ ip = public_ip_for_host(server_name)
236
+ url = url.sub(/\$\{#{server_name}\}/, ip)
237
+ end
238
+
239
+ puts "HTTP Request: #{url}"
240
+ puts `curl -s -m 5 #{url}`
241
+ end
242
+
243
+ def run_list_remove(query, entry)
244
+ nodes = search_nodes(query)
245
+ return unless nodes
246
+
247
+ nodes.each do |n|
248
+ cmd = Chef::Knife::NodeRunListRemove.new([n.name, entry])
249
+ cmd.run_with_pretty_exceptions
250
+ end
251
+ end
252
+
253
+ def find_public_ips(query)
254
+ hostnames = search_nodes(query, 'hostname')
255
+ puts "Found hostnames: #{hostnames.inspect}"
256
+ ips = hostnames.map { |h|
257
+ public_ip_for_host h
258
+ }
259
+ ips.compact.uniq
260
+ end
261
+
262
+ def public_ip_for_host(name)
263
+ return nil unless name
264
+ @public_ip_cache ||= {}
265
+
266
+ if !@public_ip_cache[name] then
267
+ server = connection.get_server(name)
268
+ return nil unless server
269
+
270
+ ip = connection.get_server_public_ip(server)
271
+ @public_ip_cache[name] = ip if ip
272
+ end
273
+
274
+ @public_ip_cache[name]
275
+ end
276
+
277
+ def get_environment
278
+ current_stack[:environment]
279
+ end
280
+
281
+ def print_local_hosts
282
+ hosts = []
283
+ current_stack[:servers].each do |server|
284
+ next unless server[:local_hosts]
285
+ name = server[:name].split(' ').first
286
+ ip = public_ip_for_host(name)
287
+ server[:local_hosts].each { |host|
288
+ hostname = host.sub(/\$\{environment\}/, get_environment)
289
+ hosts << "#{ip} #{hostname}"
290
+ }
291
+ end
292
+ unless hosts.empty?
293
+ puts "\nAdd this to your /etc/hosts file:"
294
+ puts hosts.join("\n")
295
+ end
296
+ end
297
+ end
298
+ end