cheftacular 2.5.0 → 2.6.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cheftacular/README.md +155 -63
  3. data/lib/cheftacular/actions/db_console.rb +3 -3
  4. data/lib/cheftacular/actions/deploy.rb +18 -12
  5. data/lib/cheftacular/actions/migrate.rb +1 -1
  6. data/lib/cheftacular/actions/tail.rb +1 -1
  7. data/lib/cheftacular/auditor.rb +14 -6
  8. data/lib/cheftacular/chef/data_bag.rb +1 -4
  9. data/lib/cheftacular/cheftacular.rb +19 -15
  10. data/lib/cheftacular/cloud_provider.rb +32 -0
  11. data/lib/cheftacular/dns.rb +1 -1
  12. data/lib/cheftacular/error.rb +13 -2
  13. data/lib/cheftacular/file_system.rb +122 -0
  14. data/lib/cheftacular/files/rvm.sh +55 -0
  15. data/lib/cheftacular/getter.rb +10 -3
  16. data/lib/cheftacular/helper.rb +31 -127
  17. data/lib/cheftacular/initialization_action.rb +8 -0
  18. data/lib/cheftacular/initializer.rb +104 -44
  19. data/lib/cheftacular/parser.rb +6 -0
  20. data/lib/cheftacular/stateless_actions/add_ssh_key_to_bag.rb +2 -2
  21. data/lib/cheftacular/stateless_actions/arguments.rb +9 -2
  22. data/lib/cheftacular/stateless_actions/backups.rb +1 -1
  23. data/lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap.rb +16 -5
  24. data/lib/cheftacular/stateless_actions/check_cheftacular_yml_keys.rb +79 -0
  25. data/lib/cheftacular/stateless_actions/chef_bootstrap.rb +20 -4
  26. data/lib/cheftacular/stateless_actions/chef_server.rb +78 -0
  27. data/lib/cheftacular/stateless_actions/clean_cookbooks.rb +3 -3
  28. data/lib/cheftacular/stateless_actions/clean_server_passwords.rb +3 -1
  29. data/lib/cheftacular/stateless_actions/cleanup_log_files.rb +1 -0
  30. data/lib/cheftacular/stateless_actions/client_list.rb +2 -2
  31. data/lib/cheftacular/stateless_actions/cloud.rb +30 -2
  32. data/lib/cheftacular/stateless_actions/cloud_bootstrap.rb +7 -13
  33. data/lib/cheftacular/stateless_actions/compile_audit_log.rb +1 -1
  34. data/lib/cheftacular/stateless_actions/create_git_key.rb +3 -1
  35. data/lib/cheftacular/stateless_actions/environment.rb +2 -0
  36. data/lib/cheftacular/stateless_actions/file.rb +4 -2
  37. data/lib/cheftacular/stateless_actions/fix_known_hosts.rb +2 -1
  38. data/lib/cheftacular/stateless_actions/full_bootstrap.rb +2 -0
  39. data/lib/cheftacular/stateless_actions/get_active_ssh_connections.rb +1 -1
  40. data/lib/cheftacular/stateless_actions/help.rb +9 -7
  41. data/lib/cheftacular/stateless_actions/initialize_cheftacular_yml.rb +29 -0
  42. data/lib/cheftacular/stateless_actions/initialize_data_bag_contents.rb +5 -36
  43. data/lib/cheftacular/stateless_actions/list_toggleable_roles.rb +45 -0
  44. data/lib/cheftacular/stateless_actions/location_aliases.rb +24 -0
  45. data/lib/cheftacular/stateless_actions/pass.rb +4 -4
  46. data/lib/cheftacular/stateless_actions/reinitialize.rb +0 -6
  47. data/lib/cheftacular/stateless_actions/remove_client.rb +12 -7
  48. data/lib/cheftacular/stateless_actions/role_toggle.rb +141 -0
  49. data/lib/cheftacular/stateless_actions/server_update.rb +2 -2
  50. data/lib/cheftacular/stateless_actions/update_chef_client.rb +18 -0
  51. data/lib/cheftacular/stateless_actions/upload_nodes.rb +5 -3
  52. data/lib/cheftacular/stateless_actions/upload_roles.rb +1 -1
  53. data/lib/cheftacular/version.rb +1 -1
  54. data/lib/cloud_interactor/authentication.rb +78 -40
  55. data/lib/cloud_interactor/cloud_interactor.rb +4 -1
  56. data/lib/cloud_interactor/cloud_provider.rb +19 -0
  57. data/lib/cloud_interactor/domain/create.rb +1 -1
  58. data/lib/cloud_interactor/domain/create_record.rb +1 -1
  59. data/lib/cloud_interactor/domain/destroy_record.rb +1 -1
  60. data/lib/cloud_interactor/domain/list_records.rb +1 -1
  61. data/lib/cloud_interactor/domain/update.rb +1 -1
  62. data/lib/cloud_interactor/domain/update_record.rb +6 -6
  63. data/lib/cloud_interactor/helpers.rb +1 -1
  64. data/lib/cloud_interactor/parser.rb +3 -2
  65. data/lib/cloud_interactor/region.rb +27 -0
  66. data/lib/cloud_interactor/server/create.rb +9 -0
  67. data/lib/cloud_interactor/sshkey.rb +59 -0
  68. data/lib/ridley/monkeypatches.rb +12 -0
  69. data/lib/sshkit/actions/start_task.rb +8 -2
  70. metadata +16 -2
@@ -83,7 +83,35 @@ class Cheftacular
83
83
  " 2. `read:FLAVOR SIZE` behaves the same as list unless a flavor size is supplied.",
84
84
 
85
85
  " 1. Standard servers are listed as XGB with no spaces in their size, performance servers are listed as X GB with " +
86
- "a space in their size. If you are about to create a server and are unsure, query flavors first."
86
+ "a space in their size. If you are about to create a server and are unsure, query flavors first.",
87
+
88
+ " 5. `image` first level argument for listing the images available on the cloud service",
89
+
90
+ " 1. `list` default behavior",
91
+
92
+ " 2. `read:NAME` behaves the same as list unless a specific image name is supplied",
93
+
94
+ " 6. `region` first level argument for listing the regions available on the cloud service (only supported by DigitalOcean)",
95
+
96
+ " 1. `list` default behavior",
97
+
98
+ " 2. `read:REGION` behaves the same as list unless a specific region name is supplied",
99
+
100
+ " 7. `sshkey` first level argument for listing the sshkeys added to the cloud service (only supported by DigitalOcean)",
101
+
102
+ " 1. `list` default behavior",
103
+
104
+ " 2. `read:KEY_NAME` behaves the same as list unless a specific sshkey name is supplied",
105
+
106
+ " 3. `\"create:KEY_NAME:KEY_STRING\"` creates an sshkey object. KEY_STRING must contain the entire value of the ssh public key file. " +
107
+ "The command must be enclosed in quotes.",
108
+
109
+ " 4. `destroy:KEY_NAME` destroys the sshkey object",
110
+
111
+ " 5. `bootstrap` captures the current computer's hostname and checks to see if a key matching this hostname exists on the cloud service. " +
112
+ "If the key does not exist, the command attempts to read the contents of the ~/.ssh/id_rsa.pub file and create a new key with that data and the " +
113
+ "hostname of the current computer. Run automatically when creating DigitalOcean servers. It's worth noting that if the computer's key already " +
114
+ "exists on DigitalOcean under a different name, this specific command will fail with a generic error. Please check your keys."
87
115
  ]
88
116
  ]
89
117
  end
@@ -95,7 +123,7 @@ class Cheftacular
95
123
 
96
124
  args = ARGV[1..ARGV.length] if args.empty?
97
125
 
98
- @config['cloud_interactor'] ||= CloudInteractor.new(@config['default']['authentication_bag_hash'], @options)
126
+ @config['cloud_interactor'] ||= CloudInteractor.new(@config['cheftacular'], @options)
99
127
 
100
128
  @config['cloud_interactor'].run args
101
129
  end
@@ -36,26 +36,20 @@ class Cheftacular
36
36
  raise "sshpass not installed! Please run brew install https://raw.github.com/eugeneoden/homebrew/eca9de1/Library/Formula/sshpass.rb (or get it from your repo for linux)"
37
37
  end
38
38
 
39
+ real_node_name = @config['getter'].get_current_real_node_name
40
+
39
41
  #the output of the cloud command is a hash, this hash is UPDATED every time a rax command is run so you only need to grab it when you need it
40
- @config['stateless_action'].cloud "server", "create:#{ @options['env'] }_#{ @options['node_name'] }:#{ @options['flavor_name'] }"
42
+ @config['stateless_action'].cloud "server", "create:#{ real_node_name }:#{ @options['flavor_name'] }"
41
43
 
42
- status_hash = @config['stateless_action'].cloud "server", "poll:#{ @options['env'] }_#{ @options['node_name'] }"
44
+ status_hash = @config['stateless_action'].cloud "server", "poll:#{ real_node_name }"
43
45
 
44
46
  status_hash['created_servers'].each do |server_hash|
45
- next unless server_hash['name'] == "#{ @options['env'] }_#{ @options['node_name'] }"
46
-
47
- @options['address'] = server_hash['ipv4_address']
47
+ next unless server_hash['name'] == "#{ real_node_name }"
48
48
 
49
- @options['private_address'] = server_hash['addresses']['private'][0]['addr']
49
+ @options['address'], @options['private_address'] = @config['cloud_provider'].parse_addresses_from_server_create_hash server_hash
50
50
  end
51
51
 
52
- begin
53
- @options['client_pass'] = status_hash['admin_passwords']["#{ @options['env'] }_#{ @options['node_name'] }"]
54
- rescue NoMethodError => e
55
- puts "Unable to locate an admin pass for server #{ @options['node_name'] }, does the server already exist? Exiting #{ __method__ }..."
56
-
57
- return false
58
- end
52
+ @options['client_pass'] = @config['cloud_provider'].parse_server_root_password_from_server_create_hash status_hash, real_node_name
59
53
 
60
54
  tld = @config[@options['env']]['config_bag_hash'][@options['sub_env']]['tld']
61
55
 
@@ -32,7 +32,7 @@ class Cheftacular
32
32
 
33
33
  entry_count, int_times = 1, []
34
34
 
35
- compiled_audit_hash[day].keys.each do |time|
35
+ compiled_audit_hash[day].keys.sort.each do |time|
36
36
  out << "#{ entry_count }. #{ time }"
37
37
 
38
38
  log_array_entry_count = 1
@@ -9,7 +9,9 @@ class Cheftacular
9
9
  " 1. This command will upload both the private and public key to the data bag. " +
10
10
  "The public key should be the one that matches the github user for your deployment github user.",
11
11
 
12
- " 2. `OAUTH_TOKEN` *must* be generated by logging into github and generating an access token in the account settings -> applications -> personal access tokens"
12
+ " 2. `OAUTH_TOKEN` *must* be generated by logging into github and generating an access token in the account settings -> applications -> personal access tokens",
13
+
14
+ " 3. NOTE! The ID_RSA_FILE should be in your .chef folder in the root of your home directory!"
13
15
  ]
14
16
  ]
15
17
  end
@@ -73,6 +73,8 @@ class Cheftacular
73
73
 
74
74
  #TODO INTEGRATE backups TO LOAD DATA INTO THE NEWLY BOOTED ENV
75
75
  when 'destroy'
76
+ raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops')
77
+
76
78
  if ask_on_destroy
77
79
  puts "Preparing to delete nodes in #{ @options['env'] }.\nEnter Y/y to confirm."
78
80
 
@@ -126,9 +126,11 @@ class Cheftacular
126
126
  target_loc = "#{ location }/#{ file_name }"
127
127
  puts("Beginning #{ command } run on #{ target_loc } for #{ n.name } (#{ n.public_ipaddress })") unless @options['quiet']
128
128
 
129
- download_location = @options['save_to_file'] ? @options['save_to_file'] : "#{ @config['locs']['chef-log'] }/#{ file_name }"
129
+ download_location = @options['save_to_file'] ? @options['save_to_file'] : "#{ @config['locs']['chef-log'] }/#{ file_name.split('/').last }"
130
130
 
131
131
  `scp -oStrictHostKeyChecking=no #{ @config['cheftacular']['deploy_user'] }@#{ n.public_ipaddress }:#{ location }/#{ file_name } #{ download_location } > /dev/tty`
132
+
133
+ puts "Finished downloading #{ file_name } to #{ download_location }!"
132
134
  end
133
135
  end
134
136
  end
@@ -181,4 +183,4 @@ module SSHKit
181
183
  end
182
184
  end
183
185
  end
184
- end
186
+ end
@@ -42,11 +42,12 @@ class Cheftacular
42
42
  end
43
43
 
44
44
  targets.each do |target|
45
+ puts "clearing #{ target }"
45
46
  case CONFIG['host_os']
46
47
  when /mswin|windows/i
47
48
  raise "#{ __method__ } does not support this operating system at this time"
48
49
  when /linux|arch/i
49
- cleanup_known_hosts_for_BSD_linux_architecture target
50
+ puts "#{ __method__ } does not support this operating system at this time"
50
51
  when /sunos|solaris/i
51
52
  raise "#{ __method__ } does not support this operating system at this time"
52
53
  when /darwin/i
@@ -24,6 +24,8 @@ class Cheftacular
24
24
 
25
25
  @config['initializer'].initialize_passwords @options['env'] #reset the passwords var to contain the new deploy pass set in ubuntu_bootstrap
26
26
 
27
+ @config['helper'].install_rvm_sh_file if @config['cheftacular']['install_rvm_on_boot']
28
+
27
29
  @config['stateless_action'].chef_bootstrap
28
30
  end
29
31
  end
@@ -2,7 +2,7 @@ class Cheftacular
2
2
  class StatelessActionDocumentation
3
3
  def get_active_ssh_connections
4
4
  @config['documentation']['stateless_action'] << [
5
- "`cft get_active_ssh_connections` will fetch the active ssh connections from every server and output it into your log directory."
5
+ "[NYI]`cft get_active_ssh_connections` will fetch the active ssh connections from every server and output it into your log directory."
6
6
  ]
7
7
 
8
8
  @config['documentation']['application'] << @config['documentation']['stateless_action'].last
@@ -11,6 +11,12 @@ class Cheftacular
11
11
  end
12
12
  end
13
13
 
14
+ class InitializationAction
15
+ def help
16
+
17
+ end
18
+ end
19
+
14
20
  class StatelessAction
15
21
  def help inference_modes=[]
16
22
  target_command = @options['command'] == 'help' ? ARGV[1] : ARGV[0]
@@ -45,15 +51,11 @@ class Cheftacular
45
51
 
46
52
  end if inference_modes.include?('stateless_action') || inference_modes.include?('both')
47
53
 
48
- puts @config['helper'].compile_documentation_lines('action').flatten.join("\n\n") if target_command == 'action'
49
-
50
54
  puts @config['documentation']['arguments'].flatten.join("\n\n") if target_command == 'arguments'
51
55
 
52
- puts @config['helper'].compile_documentation_lines('stateless_action').flatten.join("\n\n") if target_command == 'stateless_action'
53
-
54
- puts @config['helper'].compile_documentation_lines('application').flatten.join("\n\n") if target_command == 'application' || target_command.empty?
56
+ puts @config['helper'].compile_documentation_lines('application').flatten.join("\n\n") if target_command.empty?
55
57
 
56
- puts @config['helper'].compile_documentation_lines('devops').flatten.join("\n\n") if target_command == 'devops'
58
+ puts @config['helper'].compile_documentation_lines(target_command).flatten.join("\n\n") if target_command =~ /action|stateless_action|application|devops/
57
59
 
58
60
  if inference_modes.empty? && @config['helper'].is_not_command_or_stateless_command?(target_command)
59
61
  methods = @config['action_documentation'].public_methods(false) + @config['stateless_action_documentation'].public_methods(false)
@@ -64,7 +66,7 @@ class Cheftacular
64
66
  puts " #{ sorted_methods.at(0) }"
65
67
  puts " #{ sorted_methods.at(1) }"
66
68
  puts " #{ sorted_methods.at(2) }\n"
67
- puts "If so, please run 'cft help COMMAND' with one of the above commands or run 'hip help application' to see a list of commands"
69
+ puts "If so, please run 'cft help COMMAND' with one of the above commands or run 'cft help #{ @config['cheftacular']['mode'] }' to see a list of commands"
68
70
  end
69
71
  end
70
72
  end
@@ -0,0 +1,29 @@
1
+ class Cheftacular
2
+ class StatelessActionDocumentation
3
+ def initialize_cheftacular_yml
4
+ @config['documentation']['stateless_action'] << [
5
+ "`cft initialize_cheftacular_yml` will create a cheftacular.yml file in your config folder (and create the" +
6
+ "config folder if it does not exist). If you already have a cheftacular.yml file in the config folder, it will " +
7
+ "create a cheftacular.example.yml file that will contain the new changes / keys in the latest cheftacular version."
8
+ ]
9
+ end
10
+ end
11
+
12
+ class InitializationAction
13
+ def initialize_cheftacular_yml
14
+
15
+ end
16
+ end
17
+
18
+ class StatelessAction
19
+ def initialize_cheftacular_yml
20
+ FileUtils.mkdir_p(File.join(@config['locs']['chef-repo'], "config"))
21
+
22
+ if File.exist?(File.join(@config['locs']['chef-repo'], "config", "cheftacular.yml"))
23
+ @config['helper'].write_config_cheftacular_yml_file('cheftacular.example.yml')
24
+ else
25
+ @config['helper'].write_config_cheftacular_yml_file
26
+ end
27
+ end
28
+ end
29
+ end
@@ -10,7 +10,7 @@ class Cheftacular
10
10
 
11
11
  class StatelessAction
12
12
  def initialize_data_bag_contents env=""
13
- raise "Environment does not exist on chef server!" unless @config['chef_environments'].include?(env)
13
+ raise "Environment #{ env } does not exist on chef server!" if !env.blank? && !@config['chef_environments'].include?(env)
14
14
 
15
15
  env = ARGV[1] if env.blank?
16
16
 
@@ -29,6 +29,8 @@ class Cheftacular
29
29
  #@config['initializer'].initialize_logs_bag_contents env
30
30
 
31
31
  #@config['ChefDataBag'].initialize_node_roles_bag_contents env
32
+
33
+ exit if @options['command'] == __method__
32
34
  end
33
35
  end
34
36
 
@@ -58,48 +60,15 @@ class Cheftacular
58
60
  end
59
61
  end
60
62
 
61
- hash['cloud_auth'] = {} unless hash.has_key?('cloud_auth')
62
-
63
- unless hash['cloud_auth'].has_key?(@options['preferred_cloud'])
64
- hash['cloud_auth'][@options['preferred_cloud']] = {}
65
-
66
- puts "Critical! No Cloud credentials detected for cloud #{ @options['preferred_cloud'] }, " +
67
- "Someone will need to edit the authentication data bag with the command " +
68
- auth_fix_message +
69
- "And add the correct cloud credentials to the hash for your preferred cloud!"
70
-
71
- save_on_finish, exit_on_finish = true,true
72
- end
73
-
74
- if hash['cloud_auth'].has_key?('rackspace')
75
- if !( hash['cloud_auth']['rackspace'].has_key?('username') || hash['cloud_auth']['rackspace'].has_key?('api_key') || hash['cloud_auth']['rackspace'].has_key?('email'))
76
-
77
- hash['cloud_auth']['rackspace']['username'] = "" unless hash['cloud_auth']['rackspace'].has_key?('username')
78
- hash['cloud_auth']['rackspace']['api_key'] = "" unless hash['cloud_auth']['rackspace'].has_key?('api_key')
79
- hash['cloud_auth']['rackspace']['email'] = "" unless hash['cloud_auth']['rackspace'].has_key?('email')
80
-
81
-
82
- puts "Critical! No cloud credentials detected for the rackspace cloud_auth hash! There must be both a valid username and an api_key in this hash!"
83
- puts "Please run #{ auth_fix_message }Fill in the blank strings with your rackspace credentials."
84
-
85
- save_on_finish, exit_on_finish = true,true
86
- elsif hash['cloud_auth']['rackspace']['username'].empty? || hash['cloud_auth']['rackspace']['api_key'].empty? || hash['cloud_auth']['rackspace']['api_key'].empty?
87
- puts "Critical! Cloud credentials detected for the rackspace cloud_auth hash are blank!"
88
- puts "Please run #{ auth_fix_message }Fill in the blank strings with your rackspace credentials."
89
-
90
- exit_on_finish = true
91
- end
92
- end
93
-
94
63
  if @config['cheftacular']['git_based_deploys']
95
64
  if !hash.has_key?('git_private_key') || !hash.has_key?('git_public_key') || !hash.has_key?('git_OAuth')
96
- puts "Warning! github user credentials in default authentication bag were not found! Please run `cft help create_git_key` and then run that command itself!" unless @command == 'help'
65
+ puts "Warning! github user credentials in default authentication bag were not found! Please run `cft help create_git_key` and then run that command itself!" unless @options['command'] == 'help'
97
66
  end
98
67
  end
99
68
 
100
69
  @config['ChefDataBag'].save_authentication_bag if save_on_finish
101
70
 
102
- exit if exit_on_finish
71
+ exit if exit_on_finish && @options['command'] != 'create_git_key'
103
72
  end
104
73
 
105
74
  #User Action Generated: {"1.2.3.4-deploy-pass": "S325DSAGBCVfg5", "1.2.3.4-root-pass": "7dfDSFgb5%231", "1.2.3.4-name": "test"}
@@ -0,0 +1,45 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def list_toggleable_roles
5
+ @config['documentation']['stateless_action'] << [
6
+ "`cft list_toggleable_roles NODE_NAME` This command will allow you to see all toggleable roles for a node"
7
+ ]
8
+
9
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
10
+ end
11
+ end
12
+
13
+ class StatelessAction
14
+ def list_toggleable_roles possible_toggles=[]
15
+ @options['node_name'] = ARGV[1] unless @options['node_name']
16
+
17
+ raise "You have yet to fully configure your role toggling settings! Exiting..." if @config['cheftacular']['role_toggling'].has_key?('do_not_allow_toggling')
18
+
19
+ nodes = @config['error'].is_valid_node_name_option?
20
+
21
+ suffix = @config['cheftacular']['role_toggling']['deactivated_role_suffix']
22
+
23
+ nodes.first.run_list.each do |role|
24
+ role = role.gsub('role[','').gsub(']','')
25
+
26
+ if !role.include?(suffix) && @config['parser'].parse_role("#{ role }#{ suffix }", 'boolean')
27
+ possible_toggles << role
28
+ possible_toggles << "#{ role }#{ suffix }"
29
+
30
+ elsif role.include?(suffix) && @config['parser'].parse_role("#{ role.gsub(suffix,'') }", 'boolean')
31
+ possible_toggles << role
32
+ possible_toggles << role.gsub(suffix,'')
33
+ end
34
+ end
35
+
36
+ puts "The current run_list for #{ @options['node_name'] } is:"
37
+
38
+ ap nodes.first.run_list
39
+
40
+ puts "\nThe possible toggles for #{ @options['node_name'] } are:"
41
+
42
+ ap possible_toggles
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ class Cheftacular
2
+ class StatelessActionDocumentation
3
+ def location_aliases
4
+ @config['documentation']['stateless_action'] << [
5
+ "`cft location_aliases` will list all location aliases listed in your cheftacular.yml. These aliases can be used " +
6
+ "in the `cft file` command."
7
+ ]
8
+
9
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
10
+ end
11
+ end
12
+
13
+ class InitializationAction
14
+ def location_aliases
15
+
16
+ end
17
+ end
18
+
19
+ class StatelessAction
20
+ def location_aliases
21
+ ap @config['cheftacular']['location_aliases']
22
+ end
23
+ end
24
+ end
@@ -26,17 +26,17 @@ class Cheftacular
26
26
 
27
27
  case CONFIG['host_os']
28
28
  when /mswin|windows/i
29
- raise "#{ __method__ } does not support this operating system at this time"
29
+ #raise "#{ __method__ } does not support this operating system at this time"
30
30
  when /linux|arch/i
31
- raise "#{ __method__ } does not support this operating system at this time"
31
+ #raise "#{ __method__ } does not support this operating system at this time"
32
32
  when /sunos|solaris/i
33
- raise "#{ __method__ } does not support this operating system at this time"
33
+ #raise "#{ __method__ } does not support this operating system at this time"
34
34
  when /darwin/i
35
35
  puts "Copying #{ nodes.first.name } (#{ nodes.first.public_ipaddress }) sudo password into your clipboard"
36
36
 
37
37
  `echo '#{ @config[nodes.first.chef_environment]['server_passwords_bag_hash']["#{ nodes.first.public_ipaddress }-deploy-pass"] }' | pbcopy`
38
38
  else
39
- raise "#{ __method__ } does not support this operating system at this time"
39
+ #raise "#{ __method__ } does not support this operating system at this time"
40
40
  end
41
41
  end
42
42
  end
@@ -30,17 +30,11 @@ class Cheftacular
30
30
 
31
31
  out << `ssh -t -oStrictHostKeyChecking=no #{ chef_user }@#{ @options['address'] } "#{ sudo(@options['address']) } rm /etc/chef/client.pem"`
32
32
 
33
- #remove_client #just in case
34
-
35
33
  puts("Starting reinitialization...") unless @options['quiet']
36
34
 
37
35
  out << `#{ @config['helper'].knife_bootstrap_command }`
38
36
 
39
37
  puts(out.last) unless @options['quiet']
40
-
41
- #@options['multi-step'] = true # have the upload_nodes grab the new nodes
42
-
43
- #upload_nodes
44
38
  end
45
39
  end
46
40
  end
@@ -3,9 +3,14 @@ class Cheftacular
3
3
  class StatelessActionDocumentation
4
4
  def remove_client
5
5
  @config['documentation']['stateless_action'] << [
6
- "`cft remove_client -n NODE_NAME` removes a client (and its node data) from the chef-server. " +
6
+ "`cft remove_client NODE_NAME [destroy]` removes a client (and its node data) from the chef-server. " +
7
7
  "It also removes its dns records from the cloud service (if possible). " +
8
- "This should not be done lightly as you will have to wipe the server and trigger another chef-client run to get it to register again"
8
+ "This should not be done lightly as you will have to wipe the server and trigger another chef-client " +
9
+ "run to get it to register again. Alternatively, you can run `cft reinitialize IP_ADDRESS NODE_NAME as well.",
10
+
11
+ [
12
+ " 1. `destroy` deletes the server as well as removing it from the chef environment."
13
+ ]
9
14
  ]
10
15
  end
11
16
  end
@@ -47,15 +52,15 @@ class Cheftacular
47
52
  @config['ridley'].client.delete(client)
48
53
 
49
54
  if @options['delete_server_on_remove'] == 'destroy'
50
- @config['stateless_action'].cloud "server", "destroy:#{ @options['env'] }_#{ n.name }"
55
+ @config['stateless_action'].cloud "server", "destroy:#{ @config['getter'].get_current_real_node_name(n.name) }"
51
56
  end
52
- end
53
57
 
54
- @config[@options['env']]['addresses_bag_hash'] = @config[@options['env']]['addresses_bag'].reload.to_hash
58
+ @config[@options['env']]['addresses_bag_hash'] = @config[@options['env']]['addresses_bag'].reload.to_hash
55
59
 
56
- @config['DNS'].compile_address_hash_for_server_from_options('set_hash_to_nil')
60
+ @config['DNS'].compile_address_hash_for_server_from_options('set_hash_to_nil')
57
61
 
58
- @config['ChefDataBag'].save_addresses_bag
62
+ @config['ChefDataBag'].save_addresses_bag
63
+ end
59
64
  end
60
65
 
61
66
  puts("Done. Please verify that the output of the next line(s) match your expectations (running client-list)") if @options['verbose']
@@ -0,0 +1,141 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def role_toggle
5
+ @config['documentation']['stateless_action'] << [
6
+ "`cft role_toggle NODE_NAME ROLE_NAME activate|deactivate` This command will allow you to **toggle** roles on nodes without using `cft upload_nodes`",
7
+
8
+ [
9
+ " 1. This command uses your *role_toggling:deactivated_role_suffix* attribute set in your cheftacular.yml to toggle the role, " +
10
+ "it checks to see if the toggled name exists then sets the node's run_list to include the toggled role",
11
+
12
+ " 2. EX: `cft role_toggle apisc01 worker activate` will find the node apisc01 and attempt to toggle the worker role to on. " +
13
+ "If the node does NOT have the worker#{ @config['cheftacular']['role_toggling']['deactivated_role_suffix'] } role, then it will " +
14
+ "add it if *role_toggling:strict_roles* is set to **false**",
15
+
16
+ " 1. If *role_toggling:strict_roles* is set to true, then cheftacular would raise an error saying this role is unsettable " +
17
+ "on the node. On the other hand, if the node already has the worker#{ @config['cheftacular']['role_toggling']['deactivated_role_suffix'] }" +
18
+ "role, then this command will succeed even if *strict_roles* is set.",
19
+
20
+ " 3. In case it isn't obvious, this command ONLY supports deactivation suffix roles like worker_deactivate or worker_off, with their" +
21
+ "on counterpart just being the role itself, like \"worker\".",
22
+
23
+ " 1. Please run `cft list_toggleable_roles NODE_NAME` to get a list of your org's toggleable roles for a node."
24
+ ]
25
+ ]
26
+
27
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
28
+ end
29
+ end
30
+
31
+ class StatelessAction
32
+ def role_toggle state_toggle='', target_run_list=[], skip_confirm=false
33
+ @options['node_name'] = ARGV[1] unless @options['node_name']
34
+ @config['parser'].parse_role(ARGV[2])
35
+ state_toggle = ARGV[3] if state_toggle.blank?
36
+
37
+ raise "You have yet to fully configure your role toggling settings! Exiting..." if @config['cheftacular']['role_toggling'].has_key?('do_not_allow_toggling')
38
+ raise "You may only enter activate or deactivate for the state toggle argument for the #{ __method__ } command." unless (state_toggle =~ /activate|deactivate/) == 0
39
+
40
+ @config['initializer'].initialize_data_bags_for_environment @options['env'], false, ['node_roles']
41
+
42
+ @config['initializer'].initialize_node_roles_bag_contents @options['env']
43
+
44
+ @config['filesystem'].cleanup_file_caches('current')
45
+
46
+ nodes = @config['error'].is_valid_node_name_option?
47
+
48
+ suffix = @config['cheftacular']['role_toggling']['deactivated_role_suffix']
49
+
50
+ if @options['role'].include?(suffix)
51
+ unless @config['parser'].parse_role("#{ @options['role'].gsub(suffix,'') }", 'boolean')
52
+ puts "Role #{ @options['role'] } does not have an activated role! There is no #{ @options['role'].gsub(suffix,'') } role!"
53
+
54
+ return false
55
+ end
56
+ else
57
+ unless @config['parser'].parse_role("#{ @options['role'] }#{ suffix }", 'boolean')
58
+ puts "Role #{ @options['role'] } does not have a deactivated role! There is no #{ @options['role'] }#{ suffix } role!"
59
+
60
+ return false
61
+ end
62
+ end
63
+
64
+ current_node_roles = nodes.first.run_list
65
+
66
+ if current_node_roles.include?("role[#{ @options['role'] }]") && !@options['role'].include?(suffix)
67
+ if state_toggle == 'activate'
68
+ puts "The role #{ @options['role'] } is already activated for #{ nodes.first.name }!"
69
+ else
70
+ puts "The role #{ @options['role'] } is currently activated, setting it to #{ @options['role'] }#{ suffix }"
71
+
72
+ target_run_list = current_node_roles.map {|r| r.gsub(@options['role'], "#{ @options['role'] }#{ suffix }") if current_node_roles.include?("role[#{ @options['role'] }]") }
73
+ end
74
+ elsif current_node_roles.include?("role[#{ @options['role'] }]") && @options['role'].include?(suffix)
75
+ if state_toggle == 'activate'
76
+ puts "The role #{ @options['role'] } is currently deactivated, setting it to #{ @options['role'].gsub(suffix, '') }"
77
+
78
+ target_run_list = current_node_roles.map {|r| r.gsub(@options['role'], "#{ @options['role'].gsub(suffix, '') }") if current_node_roles.include?("role[#{ @options['role'] }]") }
79
+ else
80
+ puts "The role #{ @options['role'] } is already deactivated for #{ nodes.first.name }!"
81
+ end
82
+ elsif current_node_roles.include?("role[#{ @options['role'] }#{ suffix }]") #they passed in the reverse of a role that was already deactivated
83
+ if state_toggle == 'activate'
84
+ puts "The role #{ @options['role'] } is currently deactivated, setting it to it's activated state"
85
+
86
+ target_run_list = current_node_roles.map {|r| r.gsub("#{ @options['role'] }#{ suffix }", "#{ @options['role'] }") if current_node_roles.include?("role[#{ @options['role'] }#{ suffix }]") }
87
+ else
88
+ puts "The role #{ @options['role'] } is already deactivated for #{ nodes.first.name }!"
89
+ end
90
+ elsif current_node_roles.include?("role[#{ @options['role'].gsub(suffix, '') }]") #they passed in the reverse of a role that was already activated
91
+ if state_toggle == 'activate'
92
+ puts "The role #{ @options['role'] } is already activated for #{ nodes.first.name }!"
93
+ else
94
+ puts "The role #{ @options['role'] } is currently activated, setting it to it's deactivated state"
95
+
96
+ target_run_list = current_node_roles.map {|r| r.gsub("#{ @options['role'].gsub('suffix','') }", "#{ @options['role'] }") if current_node_roles.include?("role[#{ @options['role'].gsub('suffix','') }]") }
97
+ end
98
+ elsif !current_node_roles.include?("role[#{ @options['role'] }]") && @config['cheftacular']['role_toggling']['strict_roles']
99
+ puts "The node does not have #{ @options['role'] } and strict roles is set to true, exiting..."
100
+
101
+ return false
102
+ elsif !current_node_roles.include?("role[#{ @options['role'] }]") && !@config['cheftacular']['role_toggling']['strict_roles']
103
+ puts "The node does not have #{ @options['role'] } and strict roles is set to false, setting this new role..."
104
+
105
+ target_run_list = current_node_roles + "role[#{ @options['role'] }"
106
+ end
107
+
108
+ unless target_run_list.empty?
109
+ puts "Updating node run list for #{ nodes.first.name } from"
110
+
111
+ ap current_node_roles
112
+
113
+ puts "to:"
114
+
115
+ ap target_run_list
116
+
117
+ if skip_confirm || !@config['cheftacular']['role_toggling']['skip_confirm']
118
+ puts "Enter Y/y to confirm."
119
+
120
+ input = STDIN.gets.chomp
121
+
122
+ return false unless ( input =~ /y|Y|yes|Yes/ ) == 0
123
+ end
124
+
125
+ @config[@options['env']]['node_roles_bag_hash']['node_roles'][nodes.first.name.gsub(/\d/,'')]['run_list'] = target_run_list
126
+
127
+ nodes.first.send("run_list=", target_run_list)
128
+
129
+ nodes.first.save
130
+
131
+ @config['ChefDataBag'].save_node_roles_bag @options['env']
132
+
133
+ @config['filesystem'].cleanup_file_caches('current')
134
+
135
+ puts "Triggering deploy to set the new role..."
136
+
137
+ @config['action'].deploy
138
+ end
139
+ end
140
+ end
141
+ end
@@ -7,7 +7,7 @@ class Cheftacular
7
7
  "This should be done with caution as this *might* break something.",
8
8
 
9
9
  [
10
- " 1. `hip apt_update restart` will prompt to ask if you also want to restart all servers in a rolling restart. " +
10
+ " 1. `cft apt_update restart` will prompt to ask if you also want to restart all servers in a rolling restart. " +
11
11
  "This should be done with extreme caution and only in a worst-case scenario."
12
12
  ]
13
13
  ]
@@ -96,4 +96,4 @@ module SSHKit
96
96
  end
97
97
  end
98
98
  end
99
- end
99
+ end
@@ -0,0 +1,18 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def update_chef_client
5
+ @config['documentation']['stateless_action'] << [
6
+ "[NYI]`cft update_chef_client` attempts to update the chef-client of all nodes to the latest version. " +
7
+ "Should be done with caution and with the chef_server's version in mind."
8
+ ]
9
+ end
10
+ end
11
+
12
+ class StatelessAction
13
+ def update_chef_client
14
+ raise "Not Yet Implemented"
15
+ raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')
16
+ end
17
+ end
18
+ end