knife-cosmic 0.2.0

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