cheftacular 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/cft +4 -0
- data/bin/cftclr +4 -0
- data/bin/cheftacular +4 -0
- data/bin/client-list +4 -0
- data/lib/cheftacular/README.md +416 -0
- data/lib/cheftacular/actions/check.rb +32 -0
- data/lib/cheftacular/actions/console.rb +62 -0
- data/lib/cheftacular/actions/database.rb +13 -0
- data/lib/cheftacular/actions/db_console.rb +67 -0
- data/lib/cheftacular/actions/deploy.rb +40 -0
- data/lib/cheftacular/actions/log.rb +47 -0
- data/lib/cheftacular/actions/migrate.rb +57 -0
- data/lib/cheftacular/actions/run.rb +64 -0
- data/lib/cheftacular/actions/scale.rb +94 -0
- data/lib/cheftacular/actions/tail.rb +55 -0
- data/lib/cheftacular/actions.rb +14 -0
- data/lib/cheftacular/auditor.rb +46 -0
- data/lib/cheftacular/chef/data_bag.rb +104 -0
- data/lib/cheftacular/cheftacular.rb +55 -0
- data/lib/cheftacular/decryptors.rb +45 -0
- data/lib/cheftacular/encryptors.rb +48 -0
- data/lib/cheftacular/getters.rb +153 -0
- data/lib/cheftacular/helpers.rb +296 -0
- data/lib/cheftacular/initializers.rb +451 -0
- data/lib/cheftacular/parsers.rb +199 -0
- data/lib/cheftacular/remote_helpers.rb +30 -0
- data/lib/cheftacular/stateless_action.rb +16 -0
- data/lib/cheftacular/stateless_actions/add_ssh_key_to_bag.rb +44 -0
- data/lib/cheftacular/stateless_actions/arguments.rb +68 -0
- data/lib/cheftacular/stateless_actions/backups.rb +116 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/centos_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/coreos_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/fedora_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/redhat_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap.rb +102 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/vyatta_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/chef_bootstrap.rb +40 -0
- data/lib/cheftacular/stateless_actions/chef_environment.rb +21 -0
- data/lib/cheftacular/stateless_actions/clean_cookbooks.rb +104 -0
- data/lib/cheftacular/stateless_actions/clean_sensu_plugins.rb +19 -0
- data/lib/cheftacular/stateless_actions/clean_server_passwords.rb +14 -0
- data/lib/cheftacular/stateless_actions/cleanup_log_files.rb +14 -0
- data/lib/cheftacular/stateless_actions/client_list.rb +89 -0
- data/lib/cheftacular/stateless_actions/cloud.rb +107 -0
- data/lib/cheftacular/stateless_actions/cloud_bootstrap.rb +109 -0
- data/lib/cheftacular/stateless_actions/compile_audit_log.rb +60 -0
- data/lib/cheftacular/stateless_actions/compile_readme.rb +41 -0
- data/lib/cheftacular/stateless_actions/create_git_key.rb +67 -0
- data/lib/cheftacular/stateless_actions/disk_report.rb +75 -0
- data/lib/cheftacular/stateless_actions/environment.rb +100 -0
- data/lib/cheftacular/stateless_actions/fetch_file.rb +24 -0
- data/lib/cheftacular/stateless_actions/fix_known_hosts.rb +70 -0
- data/lib/cheftacular/stateless_actions/full_bootstrap.rb +30 -0
- data/lib/cheftacular/stateless_actions/get_active_ssh_connections.rb +18 -0
- data/lib/cheftacular/stateless_actions/get_haproxy_log.rb +55 -0
- data/lib/cheftacular/stateless_actions/get_log_from_bag.rb +38 -0
- data/lib/cheftacular/stateless_actions/get_pg_pass.rb +61 -0
- data/lib/cheftacular/stateless_actions/help.rb +71 -0
- data/lib/cheftacular/stateless_actions/initialize_data_bag_contents.rb +220 -0
- data/lib/cheftacular/stateless_actions/knife_upload.rb +23 -0
- data/lib/cheftacular/stateless_actions/pass.rb +49 -0
- data/lib/cheftacular/stateless_actions/reinitialize.rb +46 -0
- data/lib/cheftacular/stateless_actions/remove_client.rb +81 -0
- data/lib/cheftacular/stateless_actions/replication_status.rb +103 -0
- data/lib/cheftacular/stateless_actions/restart_swap.rb +55 -0
- data/lib/cheftacular/stateless_actions/rvm.rb +14 -0
- data/lib/cheftacular/stateless_actions/server_update.rb +99 -0
- data/lib/cheftacular/stateless_actions/service.rb +14 -0
- data/lib/cheftacular/stateless_actions/test_env.rb +82 -0
- data/lib/cheftacular/stateless_actions/update_split_branches.rb +64 -0
- data/lib/cheftacular/stateless_actions/update_tld.rb +62 -0
- data/lib/cheftacular/stateless_actions/upload_nodes.rb +120 -0
- data/lib/cheftacular/stateless_actions/upload_roles.rb +24 -0
- data/lib/cheftacular/version.rb +5 -0
- data/lib/cheftacular.rb +4 -0
- data/lib/cloud_interactor/authentication.rb +56 -0
- data/lib/cloud_interactor/cloud_interactor.rb +23 -0
- data/lib/cloud_interactor/domain/create.rb +17 -0
- data/lib/cloud_interactor/domain/create_record.rb +27 -0
- data/lib/cloud_interactor/domain/destroy.rb +17 -0
- data/lib/cloud_interactor/domain/destroy_record.rb +23 -0
- data/lib/cloud_interactor/domain/list.rb +9 -0
- data/lib/cloud_interactor/domain/list_records.rb +22 -0
- data/lib/cloud_interactor/domain/read.rb +23 -0
- data/lib/cloud_interactor/domain/read_record.rb +27 -0
- data/lib/cloud_interactor/domain/update.rb +18 -0
- data/lib/cloud_interactor/domain/update_record.rb +42 -0
- data/lib/cloud_interactor/domain.rb +18 -0
- data/lib/cloud_interactor/flavor.rb +27 -0
- data/lib/cloud_interactor/helpers.rb +70 -0
- data/lib/cloud_interactor/image.rb +27 -0
- data/lib/cloud_interactor/parser.rb +37 -0
- data/lib/cloud_interactor/server/attach_volume.rb +33 -0
- data/lib/cloud_interactor/server/create.rb +39 -0
- data/lib/cloud_interactor/server/destroy.rb +11 -0
- data/lib/cloud_interactor/server/detach_volume.rb +21 -0
- data/lib/cloud_interactor/server/list.rb +7 -0
- data/lib/cloud_interactor/server/list_volumes.rb +25 -0
- data/lib/cloud_interactor/server/poll.rb +22 -0
- data/lib/cloud_interactor/server/read.rb +9 -0
- data/lib/cloud_interactor/server/read_volume.rb +24 -0
- data/lib/cloud_interactor/server.rb +17 -0
- data/lib/cloud_interactor/version.rb +4 -0
- data/lib/cloud_interactor/volume/create.rb +13 -0
- data/lib/cloud_interactor/volume/destroy.rb +11 -0
- data/lib/cloud_interactor/volume/list.rb +7 -0
- data/lib/cloud_interactor/volume/read.rb +9 -0
- data/lib/cloud_interactor/volume.rb +20 -0
- data/lib/ridley/monkeypatches.rb +11 -0
- data/lib/sshkit/actions/start_commit_check.rb +19 -0
- data/lib/sshkit/actions/start_deploy.rb +25 -0
- data/lib/sshkit/actions/start_log_fetch.rb +91 -0
- data/lib/sshkit/actions/start_task.rb +29 -0
- data/lib/sshkit/getters.rb +67 -0
- data/lib/sshkit/helpers.rb +13 -0
- data/lib/sshkit/monkeypatches.rb +19 -0
- metadata +375 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
class Cheftacular
|
2
|
+
class StatelessActionDocumentation
|
3
|
+
def fetch_file
|
4
|
+
@config['documentation']['stateless_action'] << [
|
5
|
+
"`cft fetch_file NODE_NAME LOCATION_ALIAS FILE_NAME` fetches a file from the remote node. ",
|
6
|
+
|
7
|
+
[
|
8
|
+
" 1. `LOCATION_ALIAS` will be parsed as a path if it has backslash characters. Otherwise it will be parsed from your " +
|
9
|
+
"location_aliases hash in your cheftacular.yml",
|
10
|
+
|
11
|
+
" 2. `FILE_NAME` is the actual name of the file to be fetched. If no value is passed or the file does not exist in the " +
|
12
|
+
"LOCATION_ALIAS, the command will return the entries in LOCATION_ALIAS"
|
13
|
+
]
|
14
|
+
]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class StatelessAction
|
19
|
+
def fetch_file out=[]
|
20
|
+
#TODO
|
21
|
+
raise "Not yet implemented"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
class Cheftacular
|
3
|
+
class StatelessActionDocumentation
|
4
|
+
def fix_known_hosts
|
5
|
+
@config['documentation']['stateless_action'] << [
|
6
|
+
"`cft fix_known_hosts [HOSTNAME]` this command will delete entries in your known_hosts file " +
|
7
|
+
"for all the servers that are in our system (ip addresses AND dns names)",
|
8
|
+
|
9
|
+
[
|
10
|
+
" 1. Passing in a hostname will make the command only remove entries with that hostname / ip specifically"
|
11
|
+
]
|
12
|
+
]
|
13
|
+
|
14
|
+
@config['documentation']['application'] << @config['documentation']['stateless_action'].last
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class StatelessAction
|
19
|
+
def fix_known_hosts
|
20
|
+
include Config
|
21
|
+
|
22
|
+
targets = ["all"]
|
23
|
+
|
24
|
+
if ARGV[1].class == String
|
25
|
+
targets = [ARGV[1]]
|
26
|
+
end
|
27
|
+
|
28
|
+
if targets.first == 'all'
|
29
|
+
nodes = @config['getter'].get_true_node_objects(true)
|
30
|
+
arr = []
|
31
|
+
environments = (nodes.map { |n| n.chef_environment }).uniq
|
32
|
+
|
33
|
+
environments.delete("_default")
|
34
|
+
|
35
|
+
environments.each do |env|
|
36
|
+
@config[env]['addresses_bag_hash'].each do |serv_hash|
|
37
|
+
arr << serv_hash['dn'].split('.').first
|
38
|
+
arr << serv_hash['public']
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
targets = arr.uniq
|
43
|
+
end
|
44
|
+
|
45
|
+
targets.each do |target|
|
46
|
+
case CONFIG['host_os']
|
47
|
+
when /mswin|windows/i
|
48
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
49
|
+
when /linux|arch/i
|
50
|
+
cleanup_known_hosts_for_BSD_linux_architecture target
|
51
|
+
when /sunos|solaris/i
|
52
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
53
|
+
when /darwin/i
|
54
|
+
cleanup_known_hosts_for_BSD_linux_architecture target
|
55
|
+
else
|
56
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
private
|
61
|
+
|
62
|
+
def cleanup_known_hosts_for_BSD_linux_architecture target
|
63
|
+
#Removes the entire line containing the string
|
64
|
+
`sed -i '' "s/#{ target }.*//g" ~/.ssh/known_hosts`
|
65
|
+
|
66
|
+
#remove empty lines
|
67
|
+
`sed -i '' "/^$/d" ~/.ssh/known_hosts`
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
class Cheftacular
|
3
|
+
class StatelessActionDocumentation
|
4
|
+
def full_bootstrap
|
5
|
+
@config['documentation']['stateless_action'] << [
|
6
|
+
"`cft full_bootstrap ADDRESS ROOT_PASS NODE_NAME` This command performs both " +
|
7
|
+
"#{ @config['cheftacular']['preferred_cloud_os'] }_bootstrap and chef_bootstrap."
|
8
|
+
]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class StatelessAction
|
13
|
+
def full_bootstrap
|
14
|
+
raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']
|
15
|
+
|
16
|
+
@options['address'] = ARGV[1] unless @options['address']
|
17
|
+
@options['client_pass'] = ARGV[2] unless @options['client_pass']
|
18
|
+
@options['node_name'] = ARGV[3] unless @options['node_name']
|
19
|
+
|
20
|
+
case @config['cheftacular']['preferred_cloud_os']
|
21
|
+
when 'ubuntu' || 'debian' then @config['stateless_action'].ubuntu_bootstrap
|
22
|
+
else @config['stateless_action'].instance_eval("#{ @config['cheftacular']['preferred_cloud_os'] }_bootstrap")
|
23
|
+
end
|
24
|
+
|
25
|
+
@config['initializer'].initialize_passwords @options['env'] #reset the passwords var to contain the new deploy pass set in ubuntu_bootstrap
|
26
|
+
|
27
|
+
@config['stateless_action'].chef_bootstrap
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Cheftacular
|
2
|
+
class StatelessActionDocumentation
|
3
|
+
def get_active_ssh_connections
|
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."
|
6
|
+
]
|
7
|
+
|
8
|
+
@config['documentation']['application'] << @config['documentation']['stateless_action'].last
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class StatelessAction
|
13
|
+
def get_active_ssh_connections
|
14
|
+
# netstat -atn | grep ':22'
|
15
|
+
raise "Not yet implemented"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
class Cheftacular
|
3
|
+
class StatelessActionDocumentation
|
4
|
+
def get_haproxy_log
|
5
|
+
@config['documentation']['stateless_action'] << [
|
6
|
+
"`cft get_haproxy_log` this command will generate a haproxy html file for the load balancer(s) associated with a repository in the log directory. " +
|
7
|
+
"Opening this log file in the browser will show the status of that haproxy at the time of the log. ",
|
8
|
+
|
9
|
+
[
|
10
|
+
" 1. In devops mode, this command will not do anything without the -R repository passed."
|
11
|
+
]
|
12
|
+
]
|
13
|
+
|
14
|
+
@config['documentation']['application'] << @config['documentation']['stateless_action'].last
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class StatelessAction
|
19
|
+
def get_haproxy_log
|
20
|
+
nodes = @config['getter'].get_true_node_objects true
|
21
|
+
|
22
|
+
nodes = @config['parser'].exclude_nodes( nodes, [{ unless: "role[#{ @config['cheftacular']['haproxy_config']['role_name'] }]" }, { if: { not_env: @options['env'] } }])
|
23
|
+
|
24
|
+
#this must always precede on () calls so they have the instance variables they need
|
25
|
+
options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars
|
26
|
+
|
27
|
+
#on is namespaced to SSHKit::Backend::Netssh.on
|
28
|
+
on ( nodes.map { |n| "deploy@" + n.public_ipaddress } ) do |host|
|
29
|
+
n = get_node_from_address(nodes, host.hostname)
|
30
|
+
|
31
|
+
puts("Beginning haproxy log generation run for #{ n.name } (#{ n.public_ipaddress })") unless options['quiet']
|
32
|
+
|
33
|
+
start_haproxy_log_generator( n.name, n.public_ipaddress, options, locs, cheftacular, passwords)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module SSHKit
|
40
|
+
module Backend
|
41
|
+
class Netssh
|
42
|
+
def start_haproxy_log_generator name, ip_address, options, locs, cheftacular, passwords, out=[]
|
43
|
+
log_loc, timestamp = set_log_loc_and_timestamp(locs)
|
44
|
+
|
45
|
+
puts("Generating log file for haproxy for #{ name } (#{ ip_address }) at #{ log_loc }/#{ name }-haproxy-#{ timestamp }.html") unless options['quiet']
|
46
|
+
|
47
|
+
out << sudo_capture( passwords[ip_address], :curl, "localhost:#{ cheftacular['haproxy_config']['default_port'] }" )
|
48
|
+
|
49
|
+
::File.open("#{ log_loc }/#{ name }-haproxy-#{ timestamp }.html", "w") { |f| f.write(out.join("\n").scrub_pretty_text.gsub('[sudo] password for deploy: ', '')) } unless options['no_logs']
|
50
|
+
|
51
|
+
puts(out) if options['output'] || options['verbose']
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
class Cheftacular
|
3
|
+
class StatelessActionDocumentation
|
4
|
+
def get_log_from_bag
|
5
|
+
@config['documentation']['stateless_action'] << [
|
6
|
+
"`cft get_log_from_bag <NODE_NAME-COMMAND_TYPE>` this command grabs the latest command run log from the data bags " +
|
7
|
+
"and saves it to your log directory. There are different types of logs saved per server depending on command."
|
8
|
+
]
|
9
|
+
|
10
|
+
@config['documentation']['application'] << @config['documentation']['stateless_action'].last
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class StatelessAction
|
15
|
+
def get_log_from_bag
|
16
|
+
#TODO https://stackoverflow.com/questions/17882463/compressing-large-string-in-ruby
|
17
|
+
log_loc, timestamp = @config['helper'].set_log_loc_and_timestamp
|
18
|
+
|
19
|
+
@options['role'] = 'all' unless @options['role']
|
20
|
+
|
21
|
+
nodes = @config['getter'].get_true_node_objects(true)
|
22
|
+
|
23
|
+
nodes = @config['parser'].exclude_nodes( nodes, [{ unless: { env: @options['env'] }}])
|
24
|
+
|
25
|
+
nodes.each do |node|
|
26
|
+
if @config[@options['env']]['logs_bag_hash'].has_key?("#{ node.name }-deploy")
|
27
|
+
puts("Found log data in logs bag. Outputting to #{ log_loc }/#{ node.name }-deploystash-#{ @config[@options['env']]['logs_bag_hash']["#{ node.name }-deploy"][:timestamp] }.txt") unless @options['quiet']
|
28
|
+
|
29
|
+
File.open("#{ log_loc }/#{ node.name }-deploystash-#{@config[@options['env']]['logs_bag_hash']["#{ node.name }-deploy"][:timestamp] }.txt", "w") do |f|
|
30
|
+
f.write(@config[@options['env']]['logs_bag_hash']["#{ node.name }-deploy"][:text])
|
31
|
+
end
|
32
|
+
|
33
|
+
puts(@config[@options['env']]['logs_bag_hash']["#{ node.name }-deploy"][:text]) if @options['verbose']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
class Cheftacular
|
3
|
+
class StatelessActionDocumentation
|
4
|
+
def get_pg_pass
|
5
|
+
@config['documentation']['stateless_action'] << [
|
6
|
+
"`cft get_pg_pass ['clip']` command will output the current environment's pg_password to your terminal. " +
|
7
|
+
"Optionally you can pass in clip like `cft get_pg_pass clip` to have it also copy the pass to your clipboard."
|
8
|
+
]
|
9
|
+
|
10
|
+
@config['documentation']['application'] << @config['documentation']['stateless_action'].last
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class StatelessAction
|
15
|
+
def get_pg_pass clip=false, target_repos=[]
|
16
|
+
|
17
|
+
@config['parser'].parse_role(@options['role'])
|
18
|
+
|
19
|
+
clip = ARGV[1] == 'clip'
|
20
|
+
|
21
|
+
if @options['role']
|
22
|
+
target_repos << @config['cheftacular']['repositories'][@options['role']]
|
23
|
+
else
|
24
|
+
@config['cheftacular']['repositories'].each_pair do |short_repo_name, repo_hash|
|
25
|
+
target_repos << repo_hash if repo_hash['database'] == 'postgresql'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
target_repos.each do |repo_hash|
|
30
|
+
db_user = repo_hash['application_database_user']
|
31
|
+
database = repo_hash.has_key?('custom_database_name') ? repo_hash['custom_database_name'] : repo_hash['repo_name']
|
32
|
+
password = @config[@options['env']]['chef_passwords_bag_hash']['pg_pass']
|
33
|
+
|
34
|
+
ap @config[@options['env']]['chef_passwords_bag_hash']
|
35
|
+
|
36
|
+
if @config[@options['env']]['chef_passwords_bag_hash'].has_key?(repo_hash['repo_name']) && @config[@options['env']]['chef_passwords_bag_hash'][repo_hash['repo_name']].has_key?('pg_pass')
|
37
|
+
password = @config[@options['env']]['chef_passwords_bag_hash'][repo_hash['repo_name']]['pg_pass'] unless @config[@options['env']]['chef_passwords_bag_hash'][repo_hash['repo_name']]['pg_pass'].empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
puts "postgres password for user #{ db_user } in database #{ database }_#{ @options['env'] } is #{ password }"
|
41
|
+
end
|
42
|
+
|
43
|
+
if clip && target_repos.count == 1
|
44
|
+
case CONFIG['host_os']
|
45
|
+
when /mswin|windows/i
|
46
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
47
|
+
when /linux|arch/i
|
48
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
49
|
+
when /sunos|solaris/i
|
50
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
51
|
+
when /darwin/i
|
52
|
+
`echo '#{ password }' | pbcopy`
|
53
|
+
else
|
54
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
55
|
+
end
|
56
|
+
elsif clip && target_repos.count > 1
|
57
|
+
puts "Unable to insert database string into clipboard, please copy paste as normal"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class Cheftacular
|
2
|
+
class StatelessActionDocumentation
|
3
|
+
def help
|
4
|
+
@config['documentation']['stateless_action'] << [
|
5
|
+
"`cft help COMMAND|MODE` this command returns the documentation for a specific command if COMMAND matches the name of a command. " +
|
6
|
+
"Alternatively, it can be passed `action|arguments|application|current|devops|stateless_action` to fetch the commands for a specific mode." +
|
7
|
+
"Misspellings of commands will display near hits."
|
8
|
+
]
|
9
|
+
|
10
|
+
@config['documentation']['application'] << @config['documentation']['stateless_action'].last
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class StatelessAction
|
15
|
+
def help inference_modes=[]
|
16
|
+
target_command = @options['command'] == 'help' ? ARGV[1] : ARGV[0]
|
17
|
+
target_command = @config['cheftacular']['mode'] if target_command == 'current'
|
18
|
+
|
19
|
+
case target_command
|
20
|
+
when 'action' then inference_modes << 'action'
|
21
|
+
when 'application' || 'devops' then inference_modes << 'both'
|
22
|
+
when 'stateless_action' then inference_modes << 'stateless_action'
|
23
|
+
end
|
24
|
+
|
25
|
+
if @config['helper'].is_command? target_command
|
26
|
+
@config['action_documentation'].send(target_command)
|
27
|
+
|
28
|
+
puts @config['documentation']['action'].flatten.join("\n\n")
|
29
|
+
|
30
|
+
elsif @config['helper'].is_stateless_command? target_command
|
31
|
+
@config['stateless_action_documentation'].send(target_command)
|
32
|
+
|
33
|
+
puts @config['documentation']['stateless_action'].flatten.join("\n\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
@config['action_documentation'].public_methods(false).each do |method|
|
37
|
+
@config['action_documentation'].send(method)
|
38
|
+
|
39
|
+
end if inference_modes.include?('action') || inference_modes.include?('both')
|
40
|
+
|
41
|
+
@config['stateless_action_documentation'].instance_methods(false).each do |method|
|
42
|
+
@config['stateless_action_documentation'].send(method)
|
43
|
+
|
44
|
+
end if inference_modes.include?('stateless_action') || inference_modes.include?('both')
|
45
|
+
|
46
|
+
puts @config['helper'].compile_documentation_lines('action').flatten.join("\n\n") if target_command == 'action'
|
47
|
+
|
48
|
+
puts @config['documentation']['arguments'].flatten.join("\n\n") if target_command == 'arguments'
|
49
|
+
|
50
|
+
puts @config['helper'].compile_documentation_lines('stateless_action').flatten.join("\n\n") if target_command == 'stateless_action'
|
51
|
+
|
52
|
+
puts @config['helper'].compile_documentation_lines('application').flatten.join("\n\n") if target_command == 'application'
|
53
|
+
|
54
|
+
puts @config['helper'].compile_documentation_lines('devops').flatten.join("\n\n") if target_command == 'devops'
|
55
|
+
|
56
|
+
if inference_modes.empty? && @config['helper'].is_not_command_or_stateless_command?(target_command)
|
57
|
+
methods = @config['action_documentation'].public_methods(false) + @config['action_documentation'].public_methods(false)
|
58
|
+
|
59
|
+
puts methods.sort
|
60
|
+
|
61
|
+
sorted_methods = methods.uniq.sort_by { |method| @config['helper'].compare_strings(target_command, method.to_s)}
|
62
|
+
|
63
|
+
puts "Unable to find documentation for #{ target_command }, did you mean:"
|
64
|
+
puts " #{ sorted_methods.at(0) }"
|
65
|
+
puts " #{ sorted_methods.at(1) }"
|
66
|
+
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"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
class Cheftacular
|
2
|
+
class StatelessActionDocumentation
|
3
|
+
def initialize_data_bag_contents
|
4
|
+
@config['documentation']['stateless_action'] << [
|
5
|
+
"`cft initialize_data_bag_contents ENVIRONMENT_NAME` will ensure the data bags always have the correct structure before each run. " +
|
6
|
+
"This command is run every time the gem is started and if called directly, will exit after completion."
|
7
|
+
]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class StatelessAction
|
12
|
+
def initialize_data_bag_contents env
|
13
|
+
raise "Environment does not exist on chef server!" unless @config['chef_environments'].include?(env)
|
14
|
+
|
15
|
+
@config['initializer'].initialize_audit_bag_contents env
|
16
|
+
|
17
|
+
@config['initializer'].initialize_authentication_bag_contents
|
18
|
+
|
19
|
+
@config['initializer'].initialize_chef_passwords_bag_contents env
|
20
|
+
|
21
|
+
@config['initializer'].initialize_config_bag_contents env
|
22
|
+
|
23
|
+
#@config['initializer'].initialize_server_passwords_bag_contents env
|
24
|
+
|
25
|
+
@config['initializer'].initialize_addresses_bag_contents env
|
26
|
+
|
27
|
+
#@config['initializer'].initialize_logs_bag_contents env
|
28
|
+
|
29
|
+
#@config['ChefDataBag'].initialize_node_roles_bag_contents env
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Initializer
|
34
|
+
def initialize_authentication_bag_contents save_on_finish=false, exit_on_finish=false
|
35
|
+
hash = @config['default']['authentication_bag_hash']
|
36
|
+
|
37
|
+
auth_fix_message = "\n\n knife data bag edit default authentication --secret-file " +
|
38
|
+
"#{ @config['locs']['chef'] }/#{ @config['cheftacular']['data_bag_key_file'] } \n\n"
|
39
|
+
|
40
|
+
unless hash.has_key?('authorized_keys')
|
41
|
+
hash['authorized_keys'] = []
|
42
|
+
|
43
|
+
puts "Critical! No Authorized Keys for ssh detected in the default authentication bag! " +
|
44
|
+
"These must be created. Use cft add_ssh_key_to_bag \"YOUR_SSH_KEY\"."
|
45
|
+
|
46
|
+
save_on_finish, exit_on_finish = true,true
|
47
|
+
end
|
48
|
+
|
49
|
+
hash['specific_repository_authorized_keys'] = {} unless hash.has_key?('specific_repository_authorized_keys')
|
50
|
+
|
51
|
+
@config['getter'].get_repo_names_for_repositories.each_key do |repo_name|
|
52
|
+
unless hash['specific_repository_authorized_keys'].has_key?(repo_name)
|
53
|
+
hash['specific_repository_authorized_keys'][repo_name] = []
|
54
|
+
|
55
|
+
save_on_finish = true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
hash['cloud_auth'] = {} unless hash.has_key?('cloud_auth')
|
60
|
+
|
61
|
+
unless hash['cloud_auth'].has_key?(@options['preferred_cloud'])
|
62
|
+
hash['cloud_auth'][@options['preferred_cloud']] = {}
|
63
|
+
|
64
|
+
puts "Critical! No Cloud credentials detected for cloud #{ @options['preferred_cloud'] }, " +
|
65
|
+
"Someone will need to edit the authentication data bag with the command " +
|
66
|
+
auth_fix_message +
|
67
|
+
"And add the correct cloud credentials to the hash for your preferred cloud!"
|
68
|
+
|
69
|
+
save_on_finish, exit_on_finish = true,true
|
70
|
+
end
|
71
|
+
|
72
|
+
if hash['cloud_auth'].has_key?('rackspace')
|
73
|
+
if !( hash['cloud_auth']['rackspace'].has_key?('username') || hash['cloud_auth']['rackspace'].has_key?('api_key') || hash['cloud_auth']['rackspace'].has_key?('email'))
|
74
|
+
|
75
|
+
hash['cloud_auth']['rackspace']['username'] = "" unless hash['cloud_auth']['rackspace'].has_key?('username')
|
76
|
+
hash['cloud_auth']['rackspace']['api_key'] = "" unless hash['cloud_auth']['rackspace'].has_key?('api_key')
|
77
|
+
hash['cloud_auth']['rackspace']['email'] = "" unless hash['cloud_auth']['rackspace'].has_key?('email')
|
78
|
+
|
79
|
+
|
80
|
+
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!"
|
81
|
+
puts "Please run #{ auth_fix_message }Fill in the blank strings with your rackspace credentials."
|
82
|
+
|
83
|
+
save_on_finish, exit_on_finish = true,true
|
84
|
+
elsif hash['cloud_auth']['rackspace']['username'].empty? || hash['cloud_auth']['rackspace']['api_key'].empty? || hash['cloud_auth']['rackspace']['api_key'].empty?
|
85
|
+
puts "Critical! Cloud credentials detected for the rackspace cloud_auth hash are blank!"
|
86
|
+
puts "Please run #{ auth_fix_message }Fill in the blank strings with your rackspace credentials."
|
87
|
+
|
88
|
+
exit_on_finish = true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
@config['ChefDataBag'].save_authentication_bag if save_on_finish
|
93
|
+
|
94
|
+
exit if exit_on_finish
|
95
|
+
end
|
96
|
+
|
97
|
+
#User Action Generated: {"1.2.3.4-deploy-pass": "S325DSAGBCVfg5", "1.2.3.4-root-pass": "7dfDSFgb5%231", "1.2.3.4-name": "test"}
|
98
|
+
def initialize_server_passwords_bag_contents env
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
#User Action Generated: {"name": "api1", "public": "1.2.3.4", "address": "10.208.1.2", "dn":"api1.example.com", "descriptor": "lb:my-backend-codebase"}
|
103
|
+
def initialize_addresses_bag_contents env, save_on_finish=false
|
104
|
+
hash = @config[env]['addresses_bag_hash']
|
105
|
+
|
106
|
+
unless hash.has_key?('addresses')
|
107
|
+
hash['addresses'] = []
|
108
|
+
|
109
|
+
save_on_finish = true
|
110
|
+
end
|
111
|
+
|
112
|
+
@config['ChefDataBag'].save_addresses_bag(env) if save_on_finish
|
113
|
+
end
|
114
|
+
|
115
|
+
#User Action Generated: {"#{ NODE_NAME }-#{ COMMAND }": "CONTENT FROM RUN"}
|
116
|
+
def initialize_log_bag_contents env
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
#TODO Reexamine, this might cause issues with the nested hash on encrypted saves
|
121
|
+
def initialize_chef_passwords_bag_contents env, save_on_finish=false, exit_on_finish=false
|
122
|
+
hash = @config[env]['chef_passwords_bag_hash']
|
123
|
+
|
124
|
+
@config['cheftacular']['global_chef_passwords'].each_pair do |pass_key, pass_length|
|
125
|
+
hash[pass_key] = @config['helper'].gen_pass(pass_length) unless hash.has_key?(pass_key)
|
126
|
+
|
127
|
+
save_on_finish = true
|
128
|
+
end
|
129
|
+
|
130
|
+
@config['getter'].get_repo_names_for_repositories.each_pair do |repo_name, repo_hash|
|
131
|
+
hash[repo_name] = {} unless hash.has_key?(repo_name)
|
132
|
+
|
133
|
+
if repo_hash.has_key?('specific_chef_passwords')
|
134
|
+
repo_hash['specific_chef_passwords'].each_pair do |pass_key, pass_length|
|
135
|
+
unless hash[repo_name].has_key?(pass_key)
|
136
|
+
hash[repo_name][pass_key] = @config['helper'].gen_pass(pass_length)
|
137
|
+
|
138
|
+
save_on_finish = true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
save_on_finish = true unless hash[repo_name].has_key?(repo_name)
|
144
|
+
end
|
145
|
+
|
146
|
+
@config['ChefDataBag'].save_chef_passwords_bag(env) if save_on_finish
|
147
|
+
end
|
148
|
+
|
149
|
+
def initialize_config_bag_contents main_env, save_on_finish=false, exit_on_finish=false
|
150
|
+
hash = @config[main_env]['config_bag_hash']
|
151
|
+
|
152
|
+
envs_to_build_in_hash = [main_env]
|
153
|
+
|
154
|
+
config_fix_message = "\n\n knife data bag edit #{ main_env } config\n\n"
|
155
|
+
|
156
|
+
if @config['cheftacular']['split_environments'].has_key?(main_env)
|
157
|
+
@config['cheftacular']['split_environments'][main_env].each_key do |sub_env|
|
158
|
+
envs_to_build_in_hash << sub_env
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
envs_to_build_in_hash.each do |env|
|
163
|
+
if !hash[env].has_key?('tld') || ( hash[env].has_key?('tld') && hash[env]['tld'].blank? )
|
164
|
+
hash[env]['tld'] = "" unless hash[env].has_key?('tld')
|
165
|
+
|
166
|
+
puts "WARNING! The config bag in environment: #{ main_env }(sub-env: #{ env }) does not have a top level domain set!"
|
167
|
+
puts "Please run #{ config_fix_message }And update the tld key!"
|
168
|
+
|
169
|
+
save_on_finish, exit_on_finish = true,true
|
170
|
+
end
|
171
|
+
|
172
|
+
unless hash[env].has_key?('restore_backups')
|
173
|
+
hash[env]['restore_backups'] = false
|
174
|
+
|
175
|
+
save_on_finish = true
|
176
|
+
end
|
177
|
+
|
178
|
+
unless hash[env].has_key?('fetch_backups')
|
179
|
+
hash[env]['fetch_backups'] = false
|
180
|
+
|
181
|
+
save_on_finish = true
|
182
|
+
end
|
183
|
+
|
184
|
+
unless hash[env].has_key?('app_revisions')
|
185
|
+
hash[env]['app_revisions'] = {}
|
186
|
+
|
187
|
+
save_on_finish = true
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
@config['ChefDataBag'].save_config_bag(main_env) if save_on_finish
|
192
|
+
end
|
193
|
+
|
194
|
+
# User Action Generated (see Cheftacular::StatelessAction.upload_nodes)
|
195
|
+
def initialize_node_roles_bag_contents env
|
196
|
+
hash = @config[env]['node_roles_bag_hash']
|
197
|
+
|
198
|
+
unless hash.has_key?('node_roles')
|
199
|
+
hash['node_roles'] = {}
|
200
|
+
|
201
|
+
save_on_finish = true
|
202
|
+
end
|
203
|
+
|
204
|
+
@config['ChefDataBag'].save_node_roles_bag(env) if save_on_finish
|
205
|
+
end
|
206
|
+
|
207
|
+
# User Action Generated (see Cheftacular::StatelessAction.compile_audit_log)
|
208
|
+
def initialize_audit_bag_contents env, save_on_finish=false
|
209
|
+
hash = @config[env]['audit_bag_hash']
|
210
|
+
|
211
|
+
unless hash.has_key?('audit_log')
|
212
|
+
hash['audit_log'] = {}
|
213
|
+
|
214
|
+
save_on_finish = true
|
215
|
+
end
|
216
|
+
|
217
|
+
@config['ChefDataBag'].save_audit_bag(env) if save_on_finish
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
class Cheftacular
|
3
|
+
class StatelessActionDocumentation
|
4
|
+
def knife_upload
|
5
|
+
@config['documentation']['stateless_action'] << [
|
6
|
+
"`cft knife_upload` will resync the chef-server with the local chef-repo code. " +
|
7
|
+
"This command is analog for `knife upload /`"
|
8
|
+
]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class StatelessAction
|
13
|
+
def knife_upload
|
14
|
+
raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')
|
15
|
+
|
16
|
+
puts("Starting upload...") unless @options['quiet']
|
17
|
+
|
18
|
+
out = `knife upload / --chef-repo-path #{ @config['locs']['chef-repo'] }`
|
19
|
+
|
20
|
+
puts out
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
class Cheftacular
|
3
|
+
class StatelessActionDocumentation
|
4
|
+
def pass
|
5
|
+
@config['documentation']['stateless_action'] << [
|
6
|
+
"`cft pass NODE_NAME` will drop the server's sudo password into your clipboard. " +
|
7
|
+
"Useful for when you need to ssh into the server itself and try advanced linux commands"
|
8
|
+
]
|
9
|
+
|
10
|
+
@config['documentation']['application'] << @config['documentation']['stateless_action'].last
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class StatelessAction
|
15
|
+
def pass
|
16
|
+
@options['node_name'] = ARGV[1] unless @options['node_name']
|
17
|
+
|
18
|
+
raise "Too few arguments, please supply a node name" if ARGV.length < 2
|
19
|
+
|
20
|
+
nodes = @config['getter'].get_true_node_objects(true)
|
21
|
+
|
22
|
+
nodes = @config['parser'].exclude_nodes( nodes, [{ if: { not_node: @options["node_name"] } }], true )
|
23
|
+
|
24
|
+
raise "Node not found for #{ @options['node_name'] }" if nodes.empty?
|
25
|
+
|
26
|
+
if nodes.first.chef_environment != @options['env']
|
27
|
+
@config['initializer'].initialize_data_bags_for_environment nodes.first.chef_environment, false, ['server_passwords']
|
28
|
+
end
|
29
|
+
|
30
|
+
puts "The password for #{ nodes.first.name }(#{ nodes.first.public_ipaddress }) for env #{ nodes.first.chef_environment }" +
|
31
|
+
" is #{ @config[nodes.first.chef_environment]['server_passwords_bag_hash']["#{ nodes.first.public_ipaddress }-deploy-pass"] }"
|
32
|
+
|
33
|
+
case CONFIG['host_os']
|
34
|
+
when /mswin|windows/i
|
35
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
36
|
+
when /linux|arch/i
|
37
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
38
|
+
when /sunos|solaris/i
|
39
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
40
|
+
when /darwin/i
|
41
|
+
puts "Copying #{ nodes.first.name } (#{ nodes.first.public_ipaddress }) sudo password into your clipboard"
|
42
|
+
|
43
|
+
`echo '#{ @config[nodes.first.chef_environment]['server_passwords_bag_hash']["#{ nodes.first.public_ipaddress }-deploy-pass"] }' | pbcopy`
|
44
|
+
else
|
45
|
+
raise "#{ __method__ } does not support this operating system at this time"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|