Class: Cheftacular::StatelessAction

Inherits:
Object
  • Object
show all
Includes:
RbConfig
Defined in:
lib/cheftacular/stateless_action.rb,
lib/cheftacular/stateless_actions/rvm.rb,
lib/cheftacular/stateless_actions/file.rb,
lib/cheftacular/stateless_actions/help.rb,
lib/cheftacular/stateless_actions/pass.rb,
lib/cheftacular/stateless_actions/cloud.rb,
lib/cheftacular/stateless_actions/slack.rb,
lib/cheftacular/stateless_actions/backups.rb,
lib/cheftacular/stateless_actions/service.rb,
lib/cheftacular/stateless_actions/test_env.rb,
lib/cheftacular/stateless_actions/arguments.rb,
lib/cheftacular/stateless_actions/reset_bag.rb,
lib/cheftacular/stateless_actions/update_tld.rb,
lib/cheftacular/stateless_actions/chef_server.rb,
lib/cheftacular/stateless_actions/client_list.rb,
lib/cheftacular/stateless_actions/disk_report.rb,
lib/cheftacular/stateless_actions/environment.rb,
lib/cheftacular/stateless_actions/get_pg_pass.rb,
lib/cheftacular/stateless_actions/role_toggle.rb,
lib/cheftacular/stateless_actions/clear_caches.rb,
lib/cheftacular/stateless_actions/knife_upload.rb,
lib/cheftacular/stateless_actions/reinitialize.rb,
lib/cheftacular/stateless_actions/restart_swap.rb,
lib/cheftacular/stateless_actions/upload_nodes.rb,
lib/cheftacular/stateless_actions/upload_roles.rb,
lib/cheftacular/stateless_actions/remove_client.rb,
lib/cheftacular/stateless_actions/server_update.rb,
lib/cheftacular/stateless_actions/chef_bootstrap.rb,
lib/cheftacular/stateless_actions/compile_readme.rb,
lib/cheftacular/stateless_actions/create_git_key.rb,
lib/cheftacular/stateless_actions/full_bootstrap.rb,
lib/cheftacular/stateless_actions/clean_cookbooks.rb,
lib/cheftacular/stateless_actions/cloud_bootstrap.rb,
lib/cheftacular/stateless_actions/fix_known_hosts.rb,
lib/cheftacular/stateless_actions/get_haproxy_log.rb,
lib/cheftacular/stateless_actions/get_log_from_bag.rb,
lib/cheftacular/stateless_actions/location_aliases.rb,
lib/cheftacular/stateless_actions/cleanup_log_files.rb,
lib/cheftacular/stateless_actions/compile_audit_log.rb,
lib/cheftacular/stateless_actions/add_ssh_key_to_bag.rb,
lib/cheftacular/stateless_actions/cheftacular_config.rb,
lib/cheftacular/stateless_actions/replication_status.rb,
lib/cheftacular/stateless_actions/update_chef_client.rb,
lib/cheftacular/stateless_actions/cheftacular_yml_help.rb,
lib/cheftacular/stateless_actions/list_toggleable_roles.rb,
lib/cheftacular/stateless_actions/update_split_branches.rb,
lib/cheftacular/stateless_actions/clean_server_passwords.rb,
lib/cheftacular/stateless_actions/check_cheftacular_yml_keys.rb,
lib/cheftacular/stateless_actions/get_active_ssh_connections.rb,
lib/cheftacular/stateless_actions/initialize_cheftacular_yml.rb,
lib/cheftacular/stateless_actions/initialize_data_bag_contents.rb,
lib/cheftacular/stateless_actions/update_thecheftacularcookbook.rb,
lib/cheftacular/stateless_actions/bootstrappers/centos_bootstrap.rb,
lib/cheftacular/stateless_actions/bootstrappers/coreos_bootstrap.rb,
lib/cheftacular/stateless_actions/bootstrappers/fedora_bootstrap.rb,
lib/cheftacular/stateless_actions/bootstrappers/redhat_bootstrap.rb,
lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap.rb,
lib/cheftacular/stateless_actions/bootstrappers/vyatta_bootstrap.rb,
lib/cheftacular/stateless_actions/update_cloudflare_dns_from_cloud.rb,
lib/cheftacular/stateless_actions/get_shorewall_allowed_connections.rb

Instance Method Summary collapse

Constructor Details

#initialize(options, config) ⇒ StatelessAction

Returns a new instance of StatelessAction.



12
13
14
# File 'lib/cheftacular/stateless_action.rb', line 12

def initialize options, config
  @options, @config = options, config
end

Instance Method Details

#add_ssh_key_to_bag(specific_repository = "") ⇒ Object

TODO key for environment specific deploys?



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/cheftacular/stateless_actions/add_ssh_key_to_bag.rb', line 23

def add_ssh_key_to_bag specific_repository=""
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')
  
  raise "Please put quotes around your SSH public key!" if ARGV[1].length < 25 #TODO REFACTOR to accurate length of shortest key

  specific_repository = ARGV[2] if ARGV[2] && specific_repository.empty?
  
  if !specific_repository.empty? && @config['getter'].get_repo_names_for_repositories.include?(specific_repository)
    puts "The repository passed (#{ specific_repository }) is not listed in the cheftacular.yml repositories hash! Please update the hash or check your spelling!"

    return false
  end

  public_ssh_key = ARGV[1]

  if specific_repository.blank?
    @config['default']['authentication_bag_hash']["authorized_keys"] << public_ssh_key.gsub("'",'')
  else
    @config['default']['authentication_bag_hash']["specific_authorized_keys"] << public_ssh_key.gsub("'",'')
  end

  @config['ChefDataBag'].save_authentication_bag
end

#argumentsObject



70
71
72
73
74
# File 'lib/cheftacular/stateless_actions/arguments.rb', line 70

def arguments
  @config['stateless_action_documentation'].arguments

  puts @config['documentation']['arguments']
end

#backups(command = '') ⇒ Object



30
31
32
33
34
35
36
# File 'lib/cheftacular/stateless_actions/backups.rb', line 30

def backups command=''
  command = ARGV[1] if command.blank?

  raise "Unsupported command (#{ command }) for cft backups" unless command =~ /activate|deactivate|load|restore/

  self.send("backups_#{ command }")
end

#check_cheftacular_yml_keys(out = [], exit_on_missing = false, warn_on_missing = false) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/cheftacular/stateless_actions/check_cheftacular_yml_keys.rb', line 16

def check_cheftacular_yml_keys out=[], exit_on_missing=false, warn_on_missing=false
  base_message = "Your cheftacular.yml is missing the key KEY, its default value is being set to DEFAULT for this run."

  #############################2.9.0################################################

  unless @config['cheftacular']['slack'].has_key?('notify_on_deployment_args')
    #backup_config:global_backup_role_name
    base_message.gsub('KEY', 'notify_on_deployment_args').gsub('DEFAULT', 'false')

    @config['cheftacular']['slack']['notify_on_deployment_args'] = false

    warn_on_missing = true
  end

  #############################2.7.0################################################

  unless @config['cheftacular'].has_key?('backup_config')
    #backup_config:global_backup_role_name
    base_message.gsub('KEY', 'backup_config').gsub('DEFAULT', 'nil')

    warn_on_missing = true
  end

  #############################2.6.0################################################
  unless @config['cheftacular'].has_key?('route_dns_changes_via')
    puts base_message.gsub('KEY', 'route_dns_changes_via').gsub('DEFAULT', @options['preferred_cloud'])

    @config['cheftacular']['route_dns_changes_via'] = @options['preferred_cloud']

    warn_on_missing = true
  end

  unless @config['cheftacular'].has_key?('node_name_separator')
    puts base_message.gsub('KEY', 'node_name_separator').gsub('DEFAULT', '-')

    @config['cheftacular']['node_name_separator'] = '-'

    warn_on_missing = true
  end

  unless @config['cheftacular'].has_key?('cloud_authentication')
    puts (base_message.gsub('KEY', 'cloud_authentication').split(',').first + ', this is a critical issue and must be fixed.')

    exit_on_missing = true
  end

  if !@config['cheftacular'].has_key?('chef_server') && @options['command'] == 'chef_server'
    puts (base_message.gsub('KEY', 'chef_server').split(',').first + ', this is a critical issue and must be fixed to run the chef_server command.')

    exit_on_missing = true
  end

  unless @config['cheftacular'].has_key?('chef_version')
    puts (base_message.gsub('KEY', 'chef_version').split(',').first + ', this is a critical issue and must be fixed.')

    exit_on_missing = true
  end

  unless @config['cheftacular'].has_key?('pre_install_packages')
    puts base_message.gsub('KEY', 'pre_install_packages').gsub('DEFAULT', '')

    @config['cheftacular']['pre_install_packages'] = ''

    warn_on_missing = true
  end

  unless @config['cheftacular'].has_key?('role_toggling')
    puts base_message.gsub('KEY', 'role_toggling').gsub('DEFAULT', "it's default nested keys")

    @config['cheftacular']['role_toggling'] = {}
    @config['cheftacular']['role_toggling']['deactivated_role_suffix'] = '_deactivated'
    @config['cheftacular']['role_toggling']['strict_roles']            = true
    @config['cheftacular']['role_toggling']['skip_confirm']            = false
    @config['cheftacular']['role_toggling']['do_not_allow_toggling']   = true

    warn_on_missing = true
  end

  if warn_on_missing || exit_on_missing
    puts "Please enter your missing keys into your cheftacular.yml based off of the cheftacular.yml at"
    puts "\n  https://github.com/SocialCentivPublic/cheftacular/blob/master/examples/cheftacular.yml"
  end

  exit if exit_on_missing || @options['command'] == __method__
end

#chef_bootstrap(out = []) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/cheftacular/stateless_actions/chef_bootstrap.rb', line 20

def chef_bootstrap out=[]
  raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']
    
  @options['address']   = ARGV[1] unless @options['address']
  @options['node_name'] = ARGV[2] unless @options['node_name']

  #@config['stateless_action'].remove_client #just in case

  if @config['cheftacular']['chef_version'].to_i >= 12
    puts("Starting chef-client installation...") unless @options['quiet']

    commands = [
      "curl -L https://www.opscode.com/chef/install.sh > ~/chef-install.sh",
      "#{ @config['helper'].sudo(@options['address']) } bash /home/deploy/chef-install.sh",
      "rm ~/chef-install.sh"
    ]

    commands.each do |command|
      out << `ssh -t -oStrictHostKeyChecking=no #{ @config['cheftacular']['deploy_user'] }@#{ @options['address'] } "#{ command }"`

      puts(out.last) unless @options['quiet'] || @options['in_scaling']
    end
  end

  puts("Starting chef bootstrap...") unless @options['quiet']

  out << `#{ @config['helper'].knife_bootstrap_command }`

  puts(out.last) unless @options['quiet'] || @options['in_scaling']

  puts("Sending up data_bag_key file...") unless @options['quiet']

  out << `scp -oStrictHostKeyChecking=no #{ @config['locs']['chef'] }/#{ @config['cheftacular']['data_bag_key_file'] } #{ @config['cheftacular']['deploy_user'] }@#{ @options['address'] }:/home/#{ @config['cheftacular']['deploy_user'] }`

  puts("Moving key file to chef directory on server...") unless @options['quiet']

  out << `ssh -t -oStrictHostKeyChecking=no #{ @config['cheftacular']['deploy_user'] }@#{ @options['address'] } "#{ @config['helper'].sudo(@options['address']) } mv -f /home/#{ @config['cheftacular']['deploy_user'] }/#{  @config['cheftacular']['data_bag_key_file'] } /etc/chef"`

  @options['force_yes'] = true # have the upload_nodes grab the new nodes

  @config['stateless_action'].upload_nodes(true)
end

#chef_serverObject



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/cheftacular/stateless_actions/chef_server.rb', line 37

def chef_server
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')
  
  if @config['cheftacular']['chef_server'].nil? || !@config['cheftacular']['chef_server']['interactable']
    raise "Chef server is not currently set to be interactable with the chef-server command"
  end

  command = ARGV[1]

  raise "Unsupported command (#{ command }) for cft chef_server" unless command =~ /restart|processes|memory/

  command_prefix = case @config['cheftacular']['chef_server']['ssh_user']
                   when 'root' then ''
                   else             "echo #{ @config['cheftacular']['chef_server']['sudo_pass'] } | sudo -S "
                   end

  command = case command
            when 'restart'   then command_prefix + 'chef-server-ctl restart'
            when 'processes' then 'ps aux'
            when 'memory'    then 'free -m'
            end

  options = @options

  on ( @config['cheftacular']['chef_server']['ssh_user'] + "@" + @config['parser'].parse_base_chef_server_url ) do |host|

    puts "Beginning chef-server #{ command } run"

    start_chef_server_interactor(command, options)
  end
end

#cheftacular_config(command = '') ⇒ Object



27
28
29
30
31
32
33
# File 'lib/cheftacular/stateless_actions/cheftacular_config.rb', line 27

def cheftacular_config command=''
  command = ARGV[1] if command.blank?

  raise "Unsupported command (#{ command }) for cft cheftacular_config" unless command =~ /display|sync|overwrite/

  self.send("cheftacular_config_#{ command }")
end

#cheftacular_yml_help(command = '') ⇒ Object Also known as: yaml_help



22
23
24
25
# File 'lib/cheftacular/stateless_actions/cheftacular_yml_help.rb', line 22

def cheftacular_yml_help command=''
  raise "Not Yet Implemented"

end

#clean_cookbooks(local_options = {'interactive' => true}) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/cheftacular/stateless_actions/clean_cookbooks.rb', line 22

def clean_cookbooks local_options={'interactive' => true}
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  ARGV.each do |arg|
    case arg
    when "force" then local_options['interactive'] = false
    end
  end

  @config['cheftacular']['wrapper_cookbooks'].split(',').each do |wrapper_cookbook|
    wrapper_cookbook_loc = "#{ @config['locs']['cookbooks'] }/#{ wrapper_cookbook }"
    FileUtils.rm(File.expand_path("#{ wrapper_cookbook_loc }/Berksfile.lock")) if File.exists?(File.expand_path("#{ wrapper_cookbook_loc }/Berksfile.lock"))
    FileUtils.rm_rf(File.expand_path("#{ @config['locs']['berks'] }/cookbooks")) if File.exists?(File.expand_path("#{ @config['locs']['berks'] }/cookbooks"))
    
    Dir.chdir wrapper_cookbook_loc
    puts "Installing new cookbooks..."
    out = `berks install`
    puts "#{out}\nFinished... Beginning directory scanning and conflict resolution..."

    berkshelf_cookbooks = @config['filesystem'].parse_latest_berkshelf_cookbook_versions

    chef_repo_cookbooks = @config['filesystem'].parse_chef_repo_cookbook_versions

    berkshelf_cookbooks.each_pair do |berkshelf_cookbook, version|
      new_name = berkshelf_cookbook.rpartition('-').first

      if chef_repo_cookbooks.has_key?(new_name) || chef_repo_cookbooks.has_key?(berkshelf_cookbook) #don't overwrite cookbooks without user input
        if local_options['interactive']
          puts "COOKBOOK::~~~~#{ new_name }~~~~::VERSION::~~~~~~~~#{ version } VS #{ chef_repo_cookbooks[new_name] }"
          puts "\nEnter O | o | overwrite to overwrite ~~~~#{ new_name }~~~~ in the chef-repo (THIS SHOULD NOT BE DONE LIGHTLY)"
          puts "Enter N | n | no        to skip to the next conflict"
          puts "If you pass force to this script, it will always overwrite."
          #puts "If you pass a STRING of comma delimited cookbooks, it will skip these cookbooks automatically and overwrite others"
          #puts "Example: ruby ./executables/clean-cookbooks 'application_ruby,wordpress'"
          puts "Input:"
          input = STDIN.gets.chomp

          next if (input =~ /N|n|no/) == 0
        end

        next if @config['helper'].is_higher_version?(chef_repo_cookbooks[new_name], version)
      end

      cmnd = "#{ @config['locs']['berks'] }/#{ berkshelf_cookbook } #{ @config['locs']['cookbooks'] }/#{ new_name }"
      puts "Moving #{ cmnd } (#{ version }:#{ chef_repo_cookbooks[new_name] })" if @options['verbose']
      `rm -Rf #{ @config['locs']['cookbooks'] }/#{ new_name }`
      `cp -Rf #{ cmnd }`
    end
  end
end

#clean_server_passwordsObject



10
11
12
13
14
# File 'lib/cheftacular/stateless_actions/clean_server_passwords.rb', line 10

def clean_server_passwords
  #TODO clean up non-existent entries in all envs server_password bags
  raise "This method is not yet implemented"
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')
end

#cleanup_log_filesObject



10
11
12
13
# File 'lib/cheftacular/stateless_actions/cleanup_log_files.rb', line 10

def cleanup_log_files
  #TODO
  raise "This method is not yet implemented"
end

#clear_cachesObject



27
28
29
# File 'lib/cheftacular/stateless_actions/clear_caches.rb', line 27

def clear_caches
  @config['filesystem'].cleanup_file_caches('all')
end

#client_listObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/cheftacular/stateless_actions/client_list.rb', line 28

def client_list
  @config['filesystem'].cleanup_file_caches('current-nodes')

  nodes = @config['getter'].get_true_node_objects(true)

  @config['chef_environments'].each do |env|
    @config['initializer'].initialize_data_bags_for_environment env, false, ['addresses', 'server_passwords']
  end

  environments = nodes.map { |n| n.chef_environment }

  environments.uniq.each do |env|
    next if env == '_default'

    env_nodes = @config['parser'].exclude_nodes(nodes, [{ if: { not_env: env } }])
    puts "\nFound #{ env_nodes.count } #{ env } nodes:"
    out = "  #{ 'name'.ljust(22) } #{ 'ip_address'.ljust(21) }"
    out << "#{ 'private_address'.ljust(21) }"                   if @options['with_private']
    out << "#{ 'pass?'.ljust(5) } #{ 'domain'.ljust(41) }"      if @options['verbose']
    out << "#{ 'deploy_password'.ljust(21) }"                   if @options['verbose']
    out << "run_list"

    puts out

    auth_hash = @config[env]['server_passwords_bag_hash']

    addresses_hash = @config['getter'].get_addresses_hash env

    env_nodes.each do |node|
      #client = @ridley.client.find(options['node_name'])
      out = "  #{ node.chef_id.ljust(22,'_') }_#{ node.public_ipaddress.ljust(20,'_') }"

      if @options['with_private']
        if addresses_hash.has_key?(node.public_ipaddress)
          out << addresses_hash[node.public_ipaddress]['address'].ljust(20,'_')
        else
          out << ''.ljust(20,'_')
        end
      end

      if @options['verbose']

        out << "_" + auth_hash.has_key?("#{ node.public_ipaddress }-deploy-pass").to_s.ljust(5,'_') + "_"

        if addresses_hash.has_key?(node.public_ipaddress)
          out << addresses_hash[node.public_ipaddress]['dn'].ljust(40,'_')
        else
          out << ''.ljust(40,'_')
        end

        if auth_hash.has_key?("#{ node.public_ipaddress }-deploy-pass")
          out << "_" + auth_hash["#{ node.public_ipaddress }-deploy-pass"]
        else
          out << "_" + ''.ljust(@config['cheftacular']['server_password_length'],'_')
        end
      end

      out << "_#{ node.run_list.join(', ') }"
      
      puts out
    end
  end
end

#cloud(*args) ⇒ Object Also known as: aws, rax



124
125
126
127
128
129
130
131
132
# File 'lib/cheftacular/stateless_actions/cloud.rb', line 124

def cloud *args
  raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']

  args = ARGV[1..ARGV.length] if args.empty?

  @config['cloud_interactor'] ||= CloudInteractor.new(@config['cheftacular'], @options)

  @config['cloud_interactor'].run args
end

#cloud_bootstrapObject



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/cheftacular/stateless_actions/cloud_bootstrap.rb', line 31

def cloud_bootstrap
  raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']
  
  @options['node_name']   = ARGV[1] unless @options['node_name']
  @options['flavor_name'] = ARGV[2] unless @options['flavor_name']
  @options['descriptor']  = ARGV[3] if ARGV[3] && !@options['descriptor']

  if `which sshpass`.empty?
    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)"
  end

  real_node_name = @config['getter'].get_current_real_node_name

  #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
  @config['stateless_action'].cloud "server", "create:#{ real_node_name }:#{ @options['flavor_name'] }"

  status_hash = @config['stateless_action'].cloud "server", "poll:#{ real_node_name }"

  status_hash['created_servers'].each do |server_hash|
    next unless server_hash['name'] == "#{ real_node_name }"

    @options['address'], @options['private_address'] = @config['cloud_provider'].parse_addresses_from_server_create_hash server_hash
  end

  @options['client_pass'] = @config['cloud_provider'].parse_server_root_password_from_server_create_hash status_hash, real_node_name

  tld = @config[@options['env']]['config_bag_hash'][@options['sub_env']]['tld']

  target_serv_index = @config[@options['env']]['addresses_bag_hash']['addresses'].count

  compile_args = ['set_all_attributes']

  compile_args << "set_specific_domain:#{ @options['with_dn'] }" if @options['with_dn']

  address_hash = @config['DNS'].compile_address_hash_for_server_from_options(*compile_args)

  @config['DNS'].create_dns_record_for_domain_from_address_hash(@options['with_dn'], address_hash, "specific_domain_mode") if @options['with_dn']

  @config['DNS'].create_dns_record_for_domain_from_address_hash(tld, address_hash)
  
  @config['ChefDataBag'].save_addresses_bag

  @options['dont_remove_address_or_server'] = true #flag to make sure our entry isnt removed in addresses bag

  @config['stateless_action'].full_bootstrap #bootstrap server with ruby and attach it to the chef server
end

#compile_audit_log(out = []) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/cheftacular/stateless_actions/compile_audit_log.rb', line 16

def compile_audit_log out=[]
  compiled_audit_hash = {}

  @config['chef_environments'].each do |env|
    @config['initializer'].initialize_data_bags_for_environment env, false, ['audit']

    @config['initializer'].initialize_audit_bag_contents env

    @config[env]['audit_bag_hash']['audit_log'].each_pair do |day, time_log_hash|
      compiled_audit_hash[day] ||= {}
      time_log_hash.each_pair do |time, log_array|
        compiled_audit_hash[day][time] ||= []
        compiled_audit_hash[day][time] <<  log_array
      end
    end
  end

  compiled_audit_hash.keys.sort.each do |day|
    out << "# Audit Log Entries for #{ Date.parse(day) }"

    entry_count, int_times = 1, []

    compiled_audit_hash[day].keys.sort.each do |time|
      out << "#{ entry_count }. #{ time }"

      log_array_entry_count = 1

      compiled_audit_hash[day][time].each do |log_arr|
        log_arr.each do |log_hash|
          out << "    #{ log_array_entry_count }. #{ log_hash['command'] }"
          out << "        1. Hostname:  #{ log_hash['hostname'] }"
          out << "        3. Arguments: #{ log_hash['arguments'] }"
          out << "        4. Options:   #{ log_hash['options'].to_hash }"
          out << ""

          log_array_entry_count += 1
        end
      end if compiled_audit_hash[day].has_key?(time)

      entry_count += 1
    end
  end

  File.open("#{ @config['locs']['chef-log'] }/audit-log-#{ Time.now.strftime("%Y%m%d%H%M%S") }.md", "w") { |f| f.write(out.join("\n")) }
end

#compile_readme(out = []) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/cheftacular/stateless_actions/compile_readme.rb', line 20

def compile_readme out=[]
   @config['action_documentation'].public_methods(false).each do |method|
     @config['action_documentation'].send(method)
  end

  @config['stateless_action_documentation'].public_methods(false).each do |method|
     @config['stateless_action_documentation'].send(method)
  end

  out << '# Table of Contents for Cheftacular Commands'

  out << '1. [Cheftacular Arguments and Flags](https://github.com/SocialCentivPublic/cheftacular/blob/master/lib/cheftacular/README.md#arguments-and-flags-for-cheftacular)'

  out << '2. [Application Commands](https://github.com/SocialCentivPublic/cheftacular/blob/master/lib/cheftacular/README.md#commands-that-can-be-run-in-the-application-context)'

  out << '3. [DevOps Commands](https://github.com/SocialCentivPublic/cheftacular/blob/master/lib/cheftacular/README.md#commands-that-can-only-be-run-in-the-devops-context)' + "\n"
  
  out << @config['documentation']['arguments']

  out << "\n## Commands that can be run in the application context"

  out << @config['helper'].compile_documentation_lines('application')

  out << "\n## Commands that can ONLY be run in the devops context"

  out << @config['helper'].compile_documentation_lines('stateless_action')

  FileUtils.rm("#{ @config['locs']['chef-log'] }/README.md") if File.exist?("#{ @config['locs']['chef-log'] }/README.md")

  File.open("#{ @config['locs']['chef-log'] }/README.md", "w") { |f| f.write(out.flatten.join("\n\n")) }
end

#coreos_bootstrap(out = []) ⇒ Object



3
4
5
# File 'lib/cheftacular/stateless_actions/bootstrappers/coreos_bootstrap.rb', line 3

def coreos_bootstrap out=[]
  raise "Not yet implemented!"
end

#create_git_key(oauth_key = "") ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/cheftacular/stateless_actions/create_git_key.rb', line 24

def create_git_key oauth_key=""
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')
  
  case ARGV[1]
  when nil      then raise "Too few arguments, please enter the filename of the id_rsa file you want to use"
  when 'id_rsa' then raise "Sorry, you can't use your default id_rsa"
  else               key_file = ARGV[1]
  end

  case ARGV[2]
  when nil then display_oauth_notice = true
  else          oauth_key = ARGV[2]
  end

  data = File.read("#{ @config['locs']['chef'] }/#{ key_file }")
  data_pub = File.read("#{ @config['locs']['chef'] }/#{ key_file }.pub")

  hash = @config['default']['authentication_bag_hash']

  if hash.has_key?('private_key') 
    puts "Overwrite current git key in default data bag? (Y/y/N/n)"
    input = STDIN.gets.chomp

    overwrite = (input =~ /Y|y|yes/) == 0
  else overwrite = true
  end

  if overwrite

    hash['git_private_key'] = data

    hash['git_public_key'] = data_pub

    hash['git_OAuth'] = oauth_key

    @config['ChefDataBag'].save_authentication_bag

    if oauth_key.blank?
      puts "REMEMBER! You need to put a OAuth token into this data bag item!"
      puts "You need to go to github and get the auth_token for the hiplogiq deploy user!"
      puts "Copy the key and paste it inbetween the quotes.\n"
      puts "\"Oauth\": \"<PASTE YOUR OAUTH KEY HERE>\"\n\n"
      puts "Please run \nknife data bag edit default authentication --secret-file #{ @config['locs']['chef'] }/#{ @config['cheftacular']['data_bag_key_file'] }\n"
    end
  end
end

#disk_report(disk_hash = {}, out = []) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/cheftacular/stateless_actions/disk_report.rb', line 16

def disk_report disk_hash={}, out=[]
  
  nodes = @config['getter'].get_true_node_objects(true)

  nodes = @config['parser'].exclude_nodes( nodes, [{ if: { env: '_default' }}] )

  @config['chef_environments'].each do |env|
    @config['initializer'].initialize_data_bags_for_environment env, false, ['addresses', 'server_passwords']

    @config['initializer'].initialize_passwords env
  end

  options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars

  on ( nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ), in: :groups, limit: 5, wait: 2 do |host|
    n = get_node_from_address(nodes, host.hostname)

    puts "Beginning disk report run for #{ n.name } (#{ n.public_ipaddress })"

    disk_hash[n.name] = start_disk_report( n.name, n.public_ipaddress, options, locs, passwords)
  end

  disk_hash.each_pair do |serv_name, output|
    out << "#{ serv_name }:"

    line_count = 1

    output.join("\n").split("\n").each do |line|
      out << line_count == 1 ? "               #{ line }" : "  #{ line }"

      line_count += 1
    end

    out << "\n"
  end

  puts(out) if @options['no_logs'] || @options['verbose']

  log_loc, timestamp = @config['helper'].set_log_loc_and_timestamp

  puts("Generating log file for disk report at #{ log_loc }/disk-report-#{ timestamp }.txt") unless @options['quiet']

  File.open("#{ log_loc }/disk-report-#{ timestamp }.txt", "w") { |f| f.write(out.join("\n").scrub_pretty_text) } unless @options['no_logs']
end

#environment(type = "boot", ask_on_destroy = false, remove = true) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/cheftacular/stateless_actions/environment.rb', line 26

def environment type="boot", ask_on_destroy=false, remove=true
  ask_on_destroy = case @options['env']
                   when 'staging'    then true
                   when 'production' then true
                   else                   false
                   end

  type = ARGV[1] if ARGV[1]

  raise "Unknown type: #{ type }, can only be 'boot' or 'destroy'" unless (type =~ /boot|destroy/) == 0

  nodes = @config['getter'].get_true_node_objects(true)

  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: { env: @options['env'] }}])

  @options['force_yes']  = true
  @options['in_scaling'] = true

  initial_servers = @config['cheftacular']['env_boot_nodes']["#{ @options['env'] }_nodes"]

  if initial_servers.empty?
    puts "There are no servers defined for #{ @options['env'] } in the env_boot_nodes hash in your cheftacular.yml... Exiting"

    exit
  end

  case type
  when 'boot'
    initial_servers.each_pair do |name, config_hash|
      next if nodes.map { |n| n.name }.include?(name)
      config_hash ||= {}

      @options['node_name']   = name
      @options['flavor_name'] = config_hash.has_key?('flavor') ? config_hash['flavor'] : @config['cheftacular']['default_flavor_name']
      @options['descriptor']  = config_hash.has_key?('descriptor') ? config_hash['descriptor'] : name
      @options['with_dn']     = config_hash.has_key?('dns_config') ? @config['parser'].parse_to_dns(config_hash['dns_config']) : @config['parser'].parse_to_dns('NODE_NAME.ENV_TLD')

      puts("Preparing to boot server #{ @options['node_name'] } for #{ @options['env'] }!") unless @options['quiet']

      @config['stateless_action'].cloud_bootstrap

      sleep 15
    end

    @config['ChefDataBag'].save_server_passwords_bag

    @options['node_name'] = nil

    @options['role'] = 'all'

    @config['action'].deploy

    #TODO INTEGRATE backups TO LOAD DATA INTO THE NEWLY BOOTED ENV
  when 'destroy'
    raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops')
    
    if ask_on_destroy
      puts "Preparing to delete nodes in #{ @options['env'] }.\nEnter Y/y to confirm."

      input = STDIN.gets.chomp

      remove = false unless ( input =~ /y|Y|yes|Yes/ ) == 0
    end

    return false unless remove

    @options['delete_server_on_remove'] = true

    nodes.each do |node|
      @options['node_name'] = node.name

      puts("Preparing to destroy server #{ @options['node_name'] } for #{ @options['env'] }!") unless @options['quiet']

      @config['stateless_action'].remove_client

      sleep 15
    end
  end
end

#fedora_bootstrap(out = []) ⇒ Object



3
4
5
# File 'lib/cheftacular/stateless_actions/bootstrappers/fedora_bootstrap.rb', line 3

def fedora_bootstrap out=[]
  raise "Not yet implemented!"
end

#file(location = '', file_name = '', mode = '') ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/cheftacular/stateless_actions/file.rb', line 52

def file location='', file_name='',mode=''
  @options['node_name'] = ARGV[1] unless @options['node_name']
  location              = ARGV[2] if location.blank?
  mode                  = ARGV[3] if mode.blank?
  file_name             = ARGV[4] if file_name.blank?

  nodes = @config['error'].is_valid_node_name_option?

  mode = 'display' if mode.nil?
  mode = 'list'    if file_name.nil? || file_name.blank?

  interaction_mode = case mode.split(':').first
                     when 'cat'       then 'sshkit'
                     when 'display'   then 'sshkit'
                     when 'edit'      then 'ssh'
                     when /fetch|scp/ then 'scp'
                     when 'list'      then 'sshkit'
                     when 'tail'      then 'sshkit'
                     when 'tail-f'    then 'ssh'
                     else                  raise "Unsupported Mode for cft file: #{ mode }, "
                     end

  
  location = @config['parser'].parse_location_alias(location)
  command  = @config['parser'].parse_mode_into_command(mode)

  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: { env: @options['env'] }}], true )

  case interaction_mode
  when 'sshkit' then file_sshkit_execute(nodes, command, location, file_name)
  when 'ssh'    then file_ssh_execute(nodes, mode, command, location, file_name)
  when 'scp'    then file_scp_execute(nodes, command, location, file_name)
  end
end

#fix_known_hostsObject



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/cheftacular/stateless_actions/fix_known_hosts.rb', line 22

def fix_known_hosts
  targets = ["all"]

  if ARGV[1].class == String
    targets = [ARGV[1]]
  end

  if targets.first == 'all'
    nodes = @config['getter'].get_true_node_objects(true)
    arr = []

    @config['chef_environments'].each do |env|
      @config['initializer'].initialize_data_bags_for_environment env, false, ['addresses']

      @config['initializer'].initialize_addresses_bag_contents env

      @config[env]['addresses_bag_hash']['addresses'].each do |serv_hash|
        arr << serv_hash['dn']
        arr << serv_hash['public']
      end
    end

    targets = arr.uniq
  end

  targets.each do |target|
    puts "clearing #{ target }"
    case CONFIG['host_os']
    when /mswin|windows/i
      raise "#{ __method__ } does not support this operating system at this time"
    when /linux|arch/i
      puts "#{ __method__ } does not support this operating system at this time"
    when /sunos|solaris/i
      raise "#{ __method__ } does not support this operating system at this time"
    when /darwin/i
      cleanup_known_hosts_for_BSD_linux_architecture target
    else
      raise "#{ __method__ } does not support this operating system at this time"
    end
  end
end

#full_bootstrapObject



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/cheftacular/stateless_actions/full_bootstrap.rb', line 21

def full_bootstrap
  raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']

  @options['address']     = ARGV[1] unless @options['address']
  @options['client_pass'] = ARGV[2] unless @options['client_pass']
  @options['node_name']   = ARGV[3] unless @options['node_name']

  case @config['cheftacular']['preferred_cloud_os']
  when 'ubuntu' || 'debian' then @config['stateless_action'].ubuntu_bootstrap
  else                           @config['stateless_action'].instance_eval("#{ @config['cheftacular']['preferred_cloud_os'] }_bootstrap")
  end

  @config['initializer'].initialize_passwords @options['env'] #reset the passwords var to contain the new deploy pass set in ubuntu_bootstrap

  @config['helper'].install_rvm_sh_file if @config['cheftacular']['install_rvm_on_boot']

  @config['stateless_action'].chef_bootstrap
end

#get_active_ssh_connectionsObject



14
15
16
17
# File 'lib/cheftacular/stateless_actions/get_active_ssh_connections.rb', line 14

def get_active_ssh_connections
  # netstat -atn | grep ':22'
  raise "Not yet implemented"
end

#get_haproxy_logObject



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/cheftacular/stateless_actions/get_haproxy_log.rb', line 22

def get_haproxy_log
  nodes = @config['getter'].get_true_node_objects true

  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: "role[#{ @config['cheftacular']['haproxy_config']['role_name'] }]" }, { if: { not_env: @options['env'] } }])

  #this must always precede on () calls so they have the instance variables they need
  options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars

  #on is namespaced to SSHKit::Backend::Netssh.on 
  on ( nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ) do |host|
    n = get_node_from_address(nodes, host.hostname)

    puts("Beginning haproxy log generation run for #{ n.name } (#{ n.public_ipaddress })") unless options['quiet']

    start_haproxy_log_generator( n.name, n.public_ipaddress, options, locs, cheftacular, passwords)
  end
end

#get_log_from_bagObject



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/cheftacular/stateless_actions/get_log_from_bag.rb', line 18

def get_log_from_bag
  #TODO https://stackoverflow.com/questions/17882463/compressing-large-string-in-ruby
  log_loc, timestamp = @config['helper'].set_log_loc_and_timestamp

  @options['role'] = 'all' unless @options['role']

  nodes = @config['getter'].get_true_node_objects(true)

  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: { env: @options['env'] }}])

  nodes.each do |node|
    if @config[@options['env']]['logs_bag_hash'].has_key?("#{ node.name }-run")
      puts("Found log data in logs bag. Outputting to #{ log_loc }/stashedlog/#{ node.name }-deploystash-#{ @config[@options['env']]['logs_bag_hash']["#{ node.name }-run"][:timestamp] }.txt") unless @options['quiet']

      File.open("#{ log_loc }/stashedlog/#{ node.name }-deploystash-#{@config[@options['env']]['logs_bag_hash']["#{ node.name }-run"][:timestamp] }.txt", "w") do |f|
        f.write(@config[@options['env']]['logs_bag_hash']["#{ node.name }-run"][:text])
      end

      puts(@config[@options['env']]['logs_bag_hash']["#{ node.name }-run"][:text]) if @options['verbose']
    end
  end
end

#get_pg_pass(clip = false, target_repos = []) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/cheftacular/stateless_actions/get_pg_pass.rb', line 18

def get_pg_pass clip=false, target_repos=[]

  @config['parser'].parse_role(@options['role'])

  clip = ARGV[1] == 'clip'

  if @options['role']
    target_repos << @config['cheftacular']['repositories'][@options['role']]
  else
    @config['cheftacular']['repositories'].each_pair do |short_repo_name, repo_hash|
      target_repos << repo_hash if repo_hash['database'] == 'postgresql'
    end
  end

  target_repos.each do |repo_hash|
    db_user  = repo_hash['application_database_user']
    database = repo_hash.has_key?('custom_database_name') ? repo_hash['custom_database_name'] : repo_hash['repo_name']
    password = @config[@options['env']]['chef_passwords_bag_hash']['pg_pass']

    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')
      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?
    end
    
    puts "postgres password for user #{ db_user } in database #{ database }_#{ @options['env'] } is #{ password }"
  end

  if clip && target_repos.count == 1
    case CONFIG['host_os']
    when /mswin|windows/i
      raise "#{ __method__ } does not support this operating system at this time"
    when /linux|arch/i
      raise "#{ __method__ } does not support this operating system at this time"
    when /sunos|solaris/i
      raise "#{ __method__ } does not support this operating system at this time"
    when /darwin/i
      `echo '#{ password }' | pbcopy`
    else
      raise "#{ __method__ } does not support this operating system at this time"
    end
  elsif clip && target_repos.count > 1
    puts "Unable to insert database string into clipboard, please copy paste as normal"
  end
end

#get_shorewall_allowed_connections(master_log_data = '') ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/cheftacular/stateless_actions/get_shorewall_allowed_connections.rb', line 21

def get_shorewall_allowed_connections master_log_data=''

  if ARGV[1].nil?
    raise "Please pass a NODE_NAME with -n NODE_NAME" if @options['node_name'].nil? || @options['node_name'].empty?

    nodes = @config['getter'].get_true_node_objects true

    nodes = @config['parser'].exclude_nodes(nodes, [{ unless: { env: @options['env'] }}, { unless: { node: @options['node_name'] }}], true)

    #this must always precede on () calls so they have the instance variables they need
    options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars

    #on is namespaced to SSHKit::Backend::Netssh.on 
    on ( nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ) do |host|
      n = get_node_from_address(nodes, host.hostname)

      puts("Beginning shorewall log capture run for #{ n.name } (#{ n.public_ipaddress })") unless options['quiet']

      master_log_data = start_shorewall_log_capture( n.name, n.public_ipaddress, options, locs, cheftacular, passwords)
    end
  else
    master_log_file = ARGV[1]

    raise "File not found! Did you enter the path correctly?" unless File.exist?(master_log_file)

    master_log_data = File.read(File.expand_path(master_log_file))
  end

  puts("Parsing addresses from log data...") unless @options['quiet']

  addresses = {}

  master_log_data.scan(/^.*Shorewall:net2fw:ACCEPT.*SRC=([\d]+\.[\d]+\.[\d]+\.[\d]+) DST.*DPT=80.*$/).each do |ip_address|
    addresses[ip_address] ||= 0
    addresses[ip_address] += 1
  end

  final_addresses = {}
  check_count = 0
  addresses.each_pair do |address, count|
    next if count < 100
    
    domain = `dig +short -x #{ address[0] }`.chomp.split("\n").join('|')
    domain = domain[0..(domain.length-2)]

    domain = address[0] if domain.blank?

    final_addresses[domain] ||= {}
    final_addresses[domain]['addresses'] ||= []
    final_addresses[domain]['addresses'] <<  address[0] unless final_addresses[domain]['addresses'].include?(address[0])
    final_addresses[domain]['count']     =   count   unless final_addresses[domain].has_key?('count')
    final_addresses[domain]['count']     +=  count   if final_addresses[domain].has_key?('count')

    check_count += 1

    puts("Processed #{ check_count } addresses (#{ address[0] }):#{ domain }:#{ count }") unless @options['quiet']
  end

  final_addresses = final_addresses.sort_by {|key, value_hash| value_hash['count']}.to_h

  final_addresses = Hash[final_addresses.to_a.reverse]

  ap(final_addresses) if @options['verbose']

  log_loc, timestamp = @config['helper'].set_log_loc_and_timestamp

  CSV.open(File.expand_path("#{ @config['locs']['chef-log'] }/shorewall-parse-#{ timestamp }.csv"), "wb") do |csv| 
    final_addresses.each_pair do |dns, info_hash|
      csv << [dns, info_hash['addresses'].join('|'), info_hash['count']]
    end
  end
end

#help(inference_modes = []) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/cheftacular/stateless_actions/help.rb', line 24

def help inference_modes=[]
  target_command   = @options['command'] == 'help' ? ARGV[1] : ARGV[0]
  target_command   = @config['cheftacular']['mode'] if target_command == 'current'
  target_command ||= ''

  case target_command
  when 'action'                  then inference_modes << 'action'
  when 'application' || 'devops' then inference_modes << 'both'
  when 'stateless_action'        then inference_modes << 'stateless_action'
  when ''                        then inference_modes << 'short_context_descriptions'
  end

  if @config['helper'].is_command? target_command
    @config['action_documentation'].send(target_command)

    puts @config['documentation']['action'][target_command.to_sym]['long_description'].flatten.join("\n\n")
  elsif @config['helper'].is_stateless_command? target_command
    @config['stateless_action_documentation'].send(target_command)

    puts @config['documentation']['stateless_action'][target_command.to_sym]['long_description'].flatten.join("\n\n")
  end

  if inference_modes.include?('action') || inference_modes.include?('both') || inference_modes.include?('short_context_descriptions')
    @config['action_documentation'].public_methods(false).each do |method|
      @config['action_documentation'].send(method)
    end
  end

  if inference_modes.include?('action') || inference_modes.include?('both') || inference_modes.include?('short_context_descriptions')
 
    @config['stateless_action_documentation'].public_methods(false).each do |method|
      @config['stateless_action_documentation'].send(method)
    end
  end

  puts @config['documentation']['arguments'].flatten.join("\n\n") if target_command == 'arguments'

  if inference_modes.include?('short_context_descriptions')
    if @config['helper'].running_in_mode?('devops')
      puts @config['helper'].compile_short_context_descriptions(@config['documentation']['action'].merge(@config['documentation']['stateless_action']), 35)
    else
      puts @config['helper'].compile_short_context_descriptions(@config['documentation']['action'].merge(@config['documentation']['application']))
    end
  end
  
  puts @config['helper'].compile_documentation_lines(target_command).flatten.join("\n\n") if target_command =~ /action|stateless_action|application|devops/

  if inference_modes.empty? && @config['helper'].is_not_command_or_stateless_command?(target_command)
    methods = @config['action_documentation'].public_methods(false) + @config['stateless_action_documentation'].public_methods(false)

    sorted_methods = methods.uniq.sort_by { |method| @config['helper'].compare_strings(target_command, method.to_s)}

    puts "Unable to find documentation for #{ target_command }, did you mean:"
    puts "    #{ sorted_methods.at(0) }"
    puts "    #{ sorted_methods.at(1) }"
    puts "    #{ sorted_methods.at(2) }\n"
    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"
  end
end

#initialize_cheftacular_yml(example_file_to_load = 'cheftacular.yml') ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/cheftacular/stateless_actions/initialize_cheftacular_yml.rb', line 29

def initialize_cheftacular_yml example_file_to_load='cheftacular.yml'
  example_file_to_load = 'thecheftacularcookbook.cheftacular.yml' if ARGV[1] == 'TheCheftacularCookbook'
  example_file_to_load = 'application.cheftacular.yml'            if ARGV[1] == 'application'

  FileUtils.mkdir_p(File.join(@config['locs']['chef-repo'], "config"))

  if File.exist?(File.join(@config['locs']['chef-repo'], "config", "cheftacular.yml"))
    @config['helper'].write_config_cheftacular_yml_file('cheftacular.example.yml', example_file_to_load )
  else
    @config['helper'].write_config_cheftacular_yml_file('cheftacular.yml', example_file_to_load)
  end
end

#initialize_data_bag_contents(env = "") ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/cheftacular/stateless_actions/initialize_data_bag_contents.rb', line 15

def initialize_data_bag_contents env=""
  raise "Environment #{ env } does not exist on chef server!" if !env.blank? && !@config['chef_environments'].include?(env)

  env = ARGV[1] if env.blank?

  @config['initializer'].initialize_audit_bag_contents env

  @config['initializer'].initialize_authentication_bag_contents

  @config['initializer'].initialize_chef_passwords_bag_contents env

  @config['initializer'].initialize_config_bag_contents env
    
  #@config['initializer'].initialize_server_passwords_bag_contents env

  @config['initializer'].initialize_addresses_bag_contents env

  #@config['initializer'].initialize_logs_bag_contents env

  #@config['ChefDataBag'].initialize_node_roles_bag_contents env

  @config['initializer'].initialize_environment_config_bag_contents if @config['helper'].running_in_mode?('devops')

  exit if @options['command'] == __method__
end

#knife_uploadObject



16
17
18
19
20
21
22
23
24
# File 'lib/cheftacular/stateless_actions/knife_upload.rb', line 16

def knife_upload
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  puts("Starting upload...") unless @options['quiet']

  out = `knife upload / --chef-repo-path #{ @config['locs']['chef-repo'] }`

  puts out
end

#list_toggleable_roles(possible_toggles = []) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/cheftacular/stateless_actions/list_toggleable_roles.rb', line 17

def list_toggleable_roles possible_toggles=[]
  @options['node_name'] = ARGV[1] unless @options['node_name']

  raise "You have yet to fully configure your role toggling settings! Exiting..." if @config['cheftacular']['role_toggling'].has_key?('do_not_allow_toggling')

  nodes = @config['error'].is_valid_node_name_option?

  suffix = @config['cheftacular']['role_toggling']['deactivated_role_suffix']

  nodes.first.run_list.each do |role|
    role = role.gsub('role[','').gsub(']','')

    if !role.include?(suffix) && @config['parser'].parse_role("#{ role }#{ suffix }", 'boolean')
      possible_toggles << role
      possible_toggles << "#{ role }#{ suffix }"

    elsif role.include?(suffix) && @config['parser'].parse_role("#{ role.gsub(suffix,'') }", 'boolean')
      possible_toggles << role
      possible_toggles << role.gsub(suffix,'')
    end
  end

  puts "The current run_list for #{ @options['node_name'] } is:"

  ap nodes.first.run_list

  puts "\nThe possible toggles for #{ @options['node_name'] } are:"

  ap possible_toggles
end

#location_aliasesObject



23
24
25
# File 'lib/cheftacular/stateless_actions/location_aliases.rb', line 23

def location_aliases
  ap @config['cheftacular']['location_aliases']
end

#passObject



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/cheftacular/stateless_actions/pass.rb', line 18

def pass
  @options['node_name'] = ARGV[1] unless @options['node_name']

  nodes = @config['error'].is_valid_node_name_option?

  if nodes.first.chef_environment != @options['env']
    @config['initializer'].initialize_data_bags_for_environment nodes.first.chef_environment, false, ['server_passwords']
  end

  puts "The password for #{ nodes.first.name }(#{ nodes.first.public_ipaddress }) for env #{ nodes.first.chef_environment }" +
  " is #{ @config[nodes.first.chef_environment]['server_passwords_bag_hash']["#{ nodes.first.public_ipaddress }-deploy-pass"] }"

  case CONFIG['host_os']
  when /mswin|windows/i
    #raise "#{ __method__ } does not support this operating system at this time"
  when /linux|arch/i
    #raise "#{ __method__ } does not support this operating system at this time"
  when /sunos|solaris/i
    #raise "#{ __method__ } does not support this operating system at this time"
  when /darwin/i
    puts "Copying #{ nodes.first.name } (#{ nodes.first.public_ipaddress }) sudo password into your clipboard"
    
    `echo '#{ @config[nodes.first.chef_environment]['server_passwords_bag_hash']["#{ nodes.first.public_ipaddress }-deploy-pass"] }' | pbcopy`
  else
    #raise "#{ __method__ } does not support this operating system at this time"
  end
end

#redhat_bootstrap(out = []) ⇒ Object



3
4
5
# File 'lib/cheftacular/stateless_actions/bootstrappers/centos_bootstrap.rb', line 3

def redhat_bootstrap out=[]
  raise "Not yet implemented!"
end

#reinitialize(out = []) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/cheftacular/stateless_actions/reinitialize.rb', line 16

def reinitialize out=[]
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  @options['address']   = ARGV[1] unless @options['address']
  @options['node_name'] = ARGV[2] unless @options['node_name']

  puts("Sending up validator file...") unless @options['quiet']

  chef_user = @config['cheftacular']['deploy_user']

  out << `scp -oStrictHostKeyChecking=no #{ @config['locs']['chef'] }/chef-validator.pem #{ chef_user }@#{ @options['address'] }:/home/#{ chef_user }`

  puts("Moving validator file to chef directory on server...") unless @options['quiet']

  out << `ssh -t -oStrictHostKeyChecking=no #{ chef_user }@#{ @options['address'] } "#{ sudo(@options['address']) } mv -f /home/#{ chef_user }/chef-validator.pem /etc/chef/validator.pem"`

  puts("Removing original client.pem file from server...") unless @options['quiet']

  out << `ssh -t -oStrictHostKeyChecking=no #{ chef_user }@#{ @options['address'] } "#{ sudo(@options['address']) } rm /etc/chef/client.pem"`

  puts("Starting reinitialization...") unless @options['quiet']

  out << `#{ @config['helper'].knife_bootstrap_command }`

  puts(out.last) unless @options['quiet']
end

#remove_client(delete_server = false, remove = true) ⇒ Object Also known as: remove_node



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/cheftacular/stateless_actions/remove_client.rb', line 24

def remove_client delete_server=false, remove=true
  @options['node_name']               = ARGV[1] unless @options['node_name']
  @options['delete_server_on_remove'] = ARGV[2] if !@options['delete_server_on_remove'] && !@options['dont_remove_address_or_server'] && ARGV[2]
  @options['delete_server_on_remove'] = 'destroy' if delete_server || @options['delete_server_on_remove']

  raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']

  raise "The only valid argument for the 2nd argument of this command is 'destroy', please enter this or leave it blank." if ARGV[2] && ARGV[2] != 'destroy' && !@options['dont_remove_address_or_server']

  raise "Invalid arguments! Node name is blank. Please call this script as cft remove_client <node_name>" unless @options['node_name']
  
  nodes = @config['getter'].get_true_node_objects(false, true)

  nodes.each do |n|
    begin
      client = @config['ridley'].client.find(@options['node_name'])
    rescue StandardError => e
      puts "Client #{ @options['node_name'] } not found."
      return false
    end

    if @options['env'] == 'production' && !@options['force_yes']
      puts "Preparing to delete #{ @options['node_name'] } (#{ n.public_ipaddress }).\nEnter Y/y to confirm."

      input = STDIN.gets.chomp

      remove = false unless ( input =~ /y|Y|yes|Yes/ ) == 0
    end

    if remove
      puts "Removing #{ n.name } (#{ n.public_ipaddress }) from node and client list"

      @config['ridley'].node.delete(n)
      @config['ridley'].client.delete(client)

      if @options['delete_server_on_remove'] == 'destroy'
        @config['stateless_action'].cloud "server", "destroy:#{ @config['getter'].get_current_real_node_name(n.name) }"
      end

      @config[@options['env']]['addresses_bag_hash'] = @config[@options['env']]['addresses_bag'].reload.to_hash

      @config['DNS'].compile_address_hash_for_server_from_options('set_hash_to_nil')

      @config['ChefDataBag'].save_addresses_bag
    end
  end
  
  puts("Done. Please verify that the output of the next line(s) match your expectations (running client-list)") if @options['verbose']
  
  puts(`client-list`) if @options['verbose']
end

#replication_status(rep_status_hash = {}, out = []) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/cheftacular/stateless_actions/replication_status.rb', line 16

def replication_status rep_status_hash={}, out=[] 
  
  nodes = @config['getter'].get_true_node_objects(true)

  primary_nodes = @config['parser'].exclude_nodes( nodes, [{ if: { env: '_default' }}, { unless: "role[db_primary]"}] )

  slave_nodes = @config['parser'].exclude_nodes( nodes, [{ if: { env: '_default' }}, { unless: "role[db_slave]"}] )

  (primary_nodes + slave_nodes).map {|n| n.chef_environment}.uniq.each do |env|
    @config['initializer'].initialize_data_bags_for_environment env, false, ['server_passwords']

    @config['initializer'].initialize_passwords env
  end

  #this must always precede on () calls so they have the instance variables they need
  options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars

  on ( primary_nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ) do |host|
    n = get_node_from_address(nodes, host.hostname)

    puts "Beginning replication status report run for #{ n.name } (#{ n.public_ipaddress })"

    env = n.name.split('_').first

    rep_status_hash[n.name] = start_replication_report( n.name, n.public_ipaddress,  options, locs, passwords)
  end

  on ( slave_nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ) do |host|
    n = get_node_from_address(nodes, host.hostname)

    puts "Beginning slave replication status report run for #{ n.name } (#{ n.public_ipaddress })"

    env = n.name.split('_').first

    rep_status_hash[n.name] = start_slave_replication_report( n.name, n.public_ipaddress,  options, locs, passwords)
  end

  rep_status_hash.each_pair do |serv_name, output|
    out << "#{ serv_name }:"

    output.join("\n").split("\n").each do |line|
      out << "  #{ line }\n"
    end

    out << "\n"
  end

  puts(out)
end

#reset_bag(bag_name = '', bag_env = '') ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/cheftacular/stateless_actions/reset_bag.rb', line 16

def reset_bag bag_name='', bag_env=''
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  bag_name = ARGV[1]         if bag_name.blank?
  bag_env  = @options['env'] if bag_env.blank?

  begin
    @config['ChefDataBag'].send("reset_#{ bag_name }_bag")

    puts "Successfully reset bag #{ bag_name }."
  rescue NoMethodError => e
    puts "You are not able to reset the bag \"#{ bag_name }\" via reset_bag, please use knife to edit the contents.\n #{ e }"
  end

  @config['stateless_action'].clear_caches
end

#restart_swapObject



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/cheftacular/stateless_actions/restart_swap.rb', line 20

def restart_swap

  nodes = @config['getter'].get_true_node_objects(true)

  nodes = @config['parser'].exclude_nodes( nodes, [{ if: { env: '_default' }}] )

  #this must always precede on () calls so they have the instance variables they need
  options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars

  on ( nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ), in: :groups, limit: 5, wait: 2 do |host|
    n = get_node_from_address(nodes, host.hostname)

    puts "Beginning swap restart run for #{ n.name } (#{ n.public_ipaddress })"

    start_swap_restart( n.name, n.public_ipaddress, options, locs, cheftacular, passwords)
  end
end

#role_toggle(state_toggle = '', target_run_list = [], skip_confirm = false) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/cheftacular/stateless_actions/role_toggle.rb', line 39

def role_toggle state_toggle='', target_run_list=[], skip_confirm=false
  @options['node_name'] = ARGV[1] unless @options['node_name']
  @config['parser'].parse_role(ARGV[2])
  state_toggle          = ARGV[3] if state_toggle.blank?

  raise "You have yet to fully configure your role toggling settings! Exiting..." if @config['cheftacular']['role_toggling'].has_key?('do_not_allow_toggling')
  raise "You may only enter activate or deactivate for the state toggle argument for the #{ __method__ } command." unless (state_toggle =~ /activate|deactivate/) == 0

  @config['initializer'].initialize_data_bags_for_environment @options['env'], false, ['node_roles']

  @config['initializer'].initialize_node_roles_bag_contents @options['env']

  @config['filesystem'].cleanup_file_caches('current-nodes')

  nodes = @config['error'].is_valid_node_name_option?

  suffix = @config['cheftacular']['role_toggling']['deactivated_role_suffix']

  if @options['role'].include?(suffix)
    unless @config['parser'].parse_role("#{ @options['role'].gsub(suffix,'') }", 'boolean')
      puts "Role #{ @options['role'] } does not have an activated role! There is no #{ @options['role'].gsub(suffix,'') } role!"

      return false
    end
  else
    unless @config['parser'].parse_role("#{ @options['role'] }#{ suffix }", 'boolean')
      puts "Role #{ @options['role'] } does not have a deactivated role! There is no #{ @options['role'] }#{ suffix } role!"

      return false
    end
  end

  current_node_roles = nodes.first.run_list

  if current_node_roles.include?("role[#{ @options['role'] }]") && !@options['role'].include?(suffix)
    if state_toggle == 'activate'
      puts "The role #{ @options['role'] } is already activated for #{ nodes.first.name }!"
    else
      puts "The role #{ @options['role'] } is currently activated, setting it to #{ @options['role'] }#{ suffix }"

      target_run_list = current_node_roles.map {|r| r.gsub(@options['role'], "#{ @options['role'] }#{ suffix }") if current_node_roles.include?("role[#{ @options['role'] }]") }
    end
  elsif current_node_roles.include?("role[#{ @options['role'] }]") && @options['role'].include?(suffix)
    if state_toggle == 'activate'
      puts "The role #{ @options['role'] } is currently deactivated, setting it to #{ @options['role'].gsub(suffix, '') }"

      target_run_list = current_node_roles.map {|r| r.gsub(@options['role'], "#{ @options['role'].gsub(suffix, '') }") if current_node_roles.include?("role[#{ @options['role'] }]") }
    else
      puts "The role #{ @options['role'] } is already deactivated for #{ nodes.first.name }!"
    end
  elsif current_node_roles.include?("role[#{ @options['role'] }#{ suffix }]") #they passed in the reverse of a role that was already deactivated
    if state_toggle == 'activate'
      puts "The role #{ @options['role'] } is currently deactivated, setting it to it's activated state"

      target_run_list = current_node_roles.map {|r| r.gsub("#{ @options['role'] }#{ suffix }", "#{ @options['role'] }") if current_node_roles.include?("role[#{ @options['role'] }#{ suffix }]") }
    else
      puts "The role #{ @options['role'] } is already deactivated for #{ nodes.first.name }!"
    end
  elsif current_node_roles.include?("role[#{ @options['role'].gsub(suffix, '') }]") #they passed in the reverse of a role that was already activated
    if state_toggle == 'activate'
      puts "The role #{ @options['role'] } is already activated for #{ nodes.first.name }!"
    else
      puts "The role #{ @options['role'] } is currently activated, setting it to it's deactivated state"
      
      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','') }]") }
    end
  elsif !current_node_roles.include?("role[#{ @options['role'] }]") && @config['cheftacular']['role_toggling']['strict_roles']
    puts "The node does not have #{ @options['role'] } and strict roles is set to true, exiting..."

    return false
  elsif !current_node_roles.include?("role[#{ @options['role'] }]") && !@config['cheftacular']['role_toggling']['strict_roles']
    puts "The node does not have #{ @options['role'] } and strict roles is set to false, setting this new role..."

    target_run_list = current_node_roles + "role[#{ @options['role'] }"
  end

  unless target_run_list.empty?
    puts "Updating node run list for #{ nodes.first.name } from"

    ap current_node_roles

    puts "to:"

    ap target_run_list

    if skip_confirm || !@config['cheftacular']['role_toggling']['skip_confirm']
      puts "Enter Y/y to confirm."

      input = STDIN.gets.chomp

      return false unless ( input =~ /y|Y|yes|Yes/ ) == 0
    end

    @config[@options['env']]['node_roles_bag_hash']['node_roles'][nodes.first.name.gsub(/\d/,'')]['run_list'] = target_run_list

    nodes.first.send("run_list=", target_run_list)

    nodes.first.save

    @config['ChefDataBag'].save_node_roles_bag @options['env']

    @config['filesystem'].cleanup_file_caches('current-nodes')

    puts "Triggering deploy to set the new role..."

    @config['action'].deploy
  end
end

#rvm(command = '') ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/cheftacular/stateless_actions/rvm.rb', line 41

def rvm command=''
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  command = case ARGV[1]
            when nil                then 'list'
            when /list|list_rubies/ then 'list rubies'
            when 'install'          then "install #{ ARGV[2] }"
            when 'run'              then ARGV[2..(ARGV.length-1)].join(' ')
            when 'all_environments' then ARGV[2..(ARGV.length-1)].join(' ')
            when 'test'             then ARGV[2..(ARGV.length-1)].join(' ')
            when 'upgrade_rvm'      then 'get stable --auto-dotfiles'
            else                         'list'
            end

  if @config['cheftacular']['rvm_gpg_key'].nil? || @config['cheftacular']['rvm_gpg_key'].blank?
    raise "GPG Key not found in cheftacular.yml! Please update your rvm_gpg_key in the file!"
  end

  nodes = ARGV[1] == 'test' ? @config['getter'].get_true_node_objects : @config['getter'].get_true_node_objects(true)

  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: { env: @options['env'] }}] ) unless ARGV[1] == 'all_servers'

  @config['chef_environments'].each do |env|
    @config['initializer'].initialize_data_bags_for_environment env, false, ['addresses', 'server_passwords']

    @config['initializer'].initialize_passwords env
  end if ARGV[1] == 'all_servers'

  options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars

  on ( nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ), in: :groups, limit: 5, wait: 2 do |host|
    n = get_node_from_address(nodes, host.hostname)

    puts "Beginning run of \"rvm #{ command }\" for #{ n.name } (#{ n.public_ipaddress })"

    start_rvm( n.name, n.public_ipaddress, options, locs, passwords, command, cheftacular )
  end
end

#server_updateObject

TODO refactor to handling multiple server types



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/cheftacular/stateless_actions/server_update.rb', line 22

def server_update
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  @options['rolling_restart'] = true if ARGV[1] && ARGV[1] == 'restart'

  if @options['rolling_restart']
    puts "Preparing to do a rolling restart for all servers in env: #{ @options['env'] } (potential data loss).\nEnter Y/y to confirm, Q/q to exit completely."

    input = STDIN.gets.chomp

    @options['rolling_restart'] = false unless ( input =~ /y|Y|yes|Yes/ ) == 0

    exit if ( input =~ /y|Y|quit|Quit/ ) == 0
  end
  
  nodes = @config['getter'].get_true_node_objects true

  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: { env: @options['env'] }}] )

  #this must always precede on () calls so they have the instance variables they need
  options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars

  on ( nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ), in: :groups, limit: 5, wait: 5 do |host|
    n = get_node_from_address(nodes, host.hostname)

    puts "Beginning apt-get run for #{ n.name } (#{ n.public_ipaddress })"

    log_data, timestamp = start_apt_updater( n.name, n.public_ipaddress, options, locs, passwords)

    logs_bag_hash["#{ n.name }-upgrade"] = { text: log_data.scrub_pretty_text, timestamp: timestamp }
  end

  on ( nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ), in: :groups, limit: 5, wait: 120 do |host|
    n = get_node_from_address(nodes, host.hostname)

    puts "Beginning restart run for #{ n.name } (#{ n.public_ipaddress })"

    start_sys_restarter( n.name, n.public_ipaddress, options, locs, passwords)
  end if @options['rolling_restart']

  @config['ChefDataBag'].save_logs_bag
end

#serviceObject



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/cheftacular/stateless_actions/service.rb', line 25

def service
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  command = case ARGV[1]
            when nil                then 'list'
            when /list/             then 'list'
            when 'restart'          then "#{ ARGV[2] } restart"
            when 'stop'             then "#{ ARGV[2] } stop"
            when 'start'            then "#{ ARGV[2] } start"
            else                         'list'
            end

  raise "You did not pass a service to #{ ARGV[1] }" if ARGV[1] =~ /restart|stop|start/ && ARGV[2].nil?

  service_location = "#{ ARGV[2] }.conf"

  nodes = @config['getter'].get_true_node_objects

  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: { env: @options['env'] }}], true )

  options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars

  on ( nodes.map { |n| @config['cheftacular']['deploy_user'] + "@" + n.public_ipaddress } ) do |host|
    n = get_node_from_address(nodes, host.hostname)

    puts "Beginning run of \"service #{ command }\" for #{ n.name } (#{ n.public_ipaddress })"

    start_service_run( n.name, n.public_ipaddress, options, locs, passwords, command, cheftacular, service_location )
  end
end

#slack(message = '', channel = '') ⇒ Object



22
23
24
25
26
27
28
29
30
# File 'lib/cheftacular/stateless_actions/slack.rb', line 22

def slack message='', channel=''
  @slack_notifier ||= Slack::Notifier.new @config['cheftacular']['slack']['webhook'], username: 'Cheftacular'

  message = ARGV[1] if message.blank?
  channel = ARGV[2] if channel.blank?

  @slack_notifier.channel = channel.nil? ? @config['cheftacular']['slack']['default_channel'] : channel
  @slack_notifier.ping message
end

#test_env(split_env = "splitstaging", type = "boot") ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/cheftacular/stateless_actions/test_env.rb', line 27

def test_env split_env="splitstaging", type="boot"
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  env_index = @options['env'] == 'staging' ? 1 : 2

  split_env = ARGV[1] unless @options['env'] == 'staging'

  type = ARGV[env_index] if ARGV[env_index]

  split_envs = @config['cheftacular']['run_list_environments'][@options['env']]

  raise "Unknown split_env: #{ split_env }, can only be #{ split_envs.values.join(', ') }" unless (split_env =~ /#{ split_envs.values.join('|') }/) == 0

  raise "Unknown type: #{ type }, can only be 'boot' or 'destroy'" unless (type =~ /boot|destroy/) == 0

  nodes = @config['getter'].get_true_node_objects(true)

  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: "role[#{ split_env.split('split').join('split_') }]" }, { unless: { env: @options['env'] }}])

  @options['force_yes']  = true
  @options['in_scaling'] = true

  case type
  when 'boot'
    @config['cheftacular']['split_env_nodes'].each_pair do |name, config_hash|
      config_hash           ||= {}
      true_name               = name.gsub('SPLITENV', split_env)
      @options['sub_env']     = split_env
      @options['node_name']   = "#{ true_name }#{ 'p' if @options['env'] == 'production' }" 
      @options['flavor_name'] = config_hash.has_key?('flavor') ? config_hash['flavor'] : @config['cheftacular']['default_flavor_name']
      @options['descriptor']  = config_hash.has_key?('descriptor') ? "#{ config_hash['descriptor'] }-#{ split_env }" : name
      @options['with_dn']     = config_hash.has_key?('dns_config') ? @config['parser'].parse_to_dns(config_hash['dns_config']) : @config['parser'].parse_to_dns('NODE_NAME.ENV_TLD')
                                
      next if nodes.map { |n| n.name }.include?(@options['node_name'])

      puts("Preparing to boot server #{ @options['node_name'] } for #{ @options['env'] }'s #{ split_env } environment!") unless @options['quiet']

      @config['stateless_action'].cloud_bootstrap

      sleep 15
    end

    @config['ChefDataBag'].save_server_passwords_bag
  when 'destroy'
    @options['delete_server_on_remove'] = true

    nodes.each do |node|

      @options['node_name'] = node.name

      puts("Preparing to destroy server #{ @options['node_name'] } for #{ @options['env'] }'s #{ split_env } environment!") unless @options['quiet']

      @config['stateless_action'].remove_client

      sleep 15
    end
  end
end

#ubuntu_bootstrap(out = []) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap.rb', line 16

def ubuntu_bootstrap out=[]
  raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']

  @options['address']     = ARGV[1] unless @options['address']
  @options['client_pass'] = ARGV[2] unless @options['address']

  if `which sshpass`.empty?
    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)"
  end

  new_deploy_pass = @config['helper'].gen_pass(@config['cheftacular']['server_pass_length'])

  deploy_user = @config['cheftacular']['deploy_user']

  root_commands = [
    "cd /home",
    "adduser #{ deploy_user } --gecos \",,,,\" --disabled-password",
    "echo #{ deploy_user }:#{ new_deploy_pass } | chpasswd",
    "adduser #{ deploy_user } www-data",
    "adduser #{ deploy_user } sudo",
    "mkdir -p /home/#{ deploy_user }/.ssh",
    "touch /home/#{ deploy_user }/.ssh/authorized_keys && touch /home/#{ deploy_user }/.ssh/known_hosts",
    "chown -R #{ deploy_user }:www-data /home/#{ deploy_user }/.ssh",
    'sed -i "s/StrictModes yes/StrictModes yes\nPasswordAuthentication no\nUseDNS no\nAllowUsers deploy postgres\n/" /etc/ssh/sshd_config'.gsub('deploy', deploy_user),
    'sed -i "s/PermitRootLogin yes/PermitRootLogin no/" /etc/ssh/sshd_config'
  ]

  @config['default']['authentication_bag_hash']['authorized_keys'].each do |line|
    root_commands << "echo \"#{ line }\" >> /home/#{ deploy_user }/.ssh/authorized_keys"
  end

  sudo = "echo #{ new_deploy_pass } | sudo -S"

  deploy_commands = [
    "#{ sudo } apt-get update",
    "#{ sudo } apt-get install curl #{ @config['cheftacular']['pre_install_packages'] } -y",
    "#{ sudo } apt-get upgrade -y"
  ]

  final_commands = []

  if @config['cheftacular']['install_rvm_on_boot']
    deploy_commands << "gpg --keyserver hkp://keys.gnupg.net --recv-keys #{ @config['cheftacular']['rvm_gpg_key'] }"
    deploy_commands << "curl -L https://get.rvm.io | bash -s stable"

    rvm_source = "source /home/deploy/.rvm/bin/rvm &&"

    final_commands = [
      "#{ rvm_source } echo '#{ new_deploy_pass }' | rvmsudo -S rvm requirements",
      "#{ rvm_source } rvm install #{ @config['cheftacular']['ruby_version'] }",
      "#{ rvm_source } rvm alias create default #{ @config['cheftacular']['ruby_version'] }",
      "#{ rvm_source } rvm gemset empty --force"
    ]

    final_commands << "#{ rvm_source } rvm install 1.9.3-p327" if @config['cheftacular']['chef_version'].to_i < 12
  end
  
  root_execute_string = "sshpass -p \"#{ @options['client_pass'] }\" ssh -t -oStrictHostKeyChecking=no root@#{ @options['address'] } '#{ root_commands.join(' && ') } && service ssh restart'"

  while system(root_execute_string) != true
    tries ||= 5
    puts "Unable to complete step 1 of setup process, trying again in 60 seconds, there are #{ tries } more tries"
    sleep 60
    tries -= 1
    raise "Unable to complete step 1 of setup process!" if tries <= 0
  end

  out << $?.to_s #output from the system command above

  puts("Finished initial setup...stage 1 of 3 for server #{ @options['address'] }") if @options['in_scaling']

  puts(out.last) unless @options['quiet'] || @options['in_scaling']

  deploy_commands.each do |cmnd|
    puts("(#{ @options['address'] }) Running #{ cmnd.gsub("#{ new_deploy_pass }", "sudo password") }") unless @options['quiet'] || @options['in_scaling']
    
    out << `ssh -t -oStrictHostKeyChecking=no #{ deploy_user }@#{ @options['address'] } "#{ cmnd }"`

    puts(out.last) unless @options['quiet'] || @options['in_scaling']
  end

  puts("Finished deploy setup....stage 2 of 3 for server #{ @options['address'] }") if @options['in_scaling']

  final_commands.each do |cmnd|
    puts "(#{ @options['address'] }) Running #{ cmnd.gsub("#{ new_deploy_pass }", "sudo password") }"

    out << `ssh -t -oStrictHostKeyChecking=no #{ deploy_user }@#{ @options['address'] } "#{ cmnd }"`

    puts(out.last) unless @options['quiet'] || @options['in_scaling']
  end

  puts("Finished ruby setup......stage 3 of 3 for server #{ @options['address'] }") if @options['in_scaling']

  @config[@options['env']]['server_passwords_bag_hash']["#{ @options['address'] }-root-pass"]   = @options['client_pass']
  @config[@options['env']]['server_passwords_bag_hash']["#{ @options['address'] }-deploy-pass"] = new_deploy_pass
  @config[@options['env']]['server_passwords_bag_hash']["#{ @options['address'] }-name"]        = @options['node_name'] if @options['node_name']

  @config['ChefDataBag'].save_server_passwords_bag unless @options['in_scaling']
end

#update_chef_clientObject



14
15
16
17
# File 'lib/cheftacular/stateless_actions/update_chef_client.rb', line 14

def update_chef_client
  raise "Not Yet Implemented"
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')
end

#update_cloudflare_dns_from_cloudObject



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/cheftacular/stateless_actions/update_cloudflare_dns_from_cloud.rb', line 26

def update_cloudflare_dns_from_cloud
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  target_domain = @config[@options['env']]['config_bag_hash'][@options['sub_env']]['tld']

  @config['stateless_action'].update_tld 'self' unless ARGV[1] == 'skip_update_tld'

  target_domain_records = @config['stateless_action'].cloud('domain', "read:#{ target_domain }")["records_for_#{ target_domain }"]

  @config['DNS'].update_cloudflare_from_array_of_domain_hashes target_domain, target_domain_records
end

#update_split_branchesObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/cheftacular/stateless_actions/update_split_branches.rb', line 28

def update_split_branches
  target_loc = @config['helper'].running_in_mode?('application') ? @config['locs']['app-root'] : "#{ @config['locs']['root'] }/#{ @options['repository'] }"

  current_revision = `cd #{ target_loc } && git rev-parse --abbrev-ref HEAD`
  
  puts "Preparing to run merges..."

  split_branch_repos =  @config['getter'].get_split_branch_hash

  raise "unsupported codebase, please run in #{ split_branch_repos.keys.join(', ') } only!" if ( @options['repository'] =~ /#{ split_branch_repos.keys.join('|') }/ ) == 0

  test_for_changes = `cd #{ target_loc } && git diff --exit-code`

  unless test_for_changes.empty?
    puts "You have changes in your current working tree for #{ target_loc }. Please commit these changes before running this command."

    exit
  end

  commands = [
    "cd #{ target_loc }",
    "git checkout master",
    "git pull origin master",
    "git fetch origin",
  ]

  @config['run_list_environments'].each_pair do |env, branch_hash|
    branch_hash.keys.each do |branch_name|        
      true_branch_name = branch_name.gsub('_','-')

      commands << ["git checkout #{ true_branch_name }", "git pull origin #{ true_branch_name }", 'git merge master --no-edit', "git push origin #{ true_branch_name }"]
    end
  end

  commands << "git checkout #{ current_revision }"

  puts `#{ commands.flatten.join(' && ') }` unless @options['quiet']

  puts "Update split branches complete. You have been returned to the branch you were on before which was \"#{ current_revision.chomp }\"."
end

#update_thecheftacularcookbook(local_options = {'interactive' => true}) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/cheftacular/stateless_actions/update_thecheftacularcookbook.rb', line 15

def update_thecheftacularcookbook local_options={'interactive' => true}
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')

  @config['cheftacular']['wrapper_cookbooks'].split(',').each do |wrapper_cookbook|
    wrapper_cookbook_loc = "#{ @config['locs']['cookbooks'] }/#{ wrapper_cookbook }"
    FileUtils.rm_rf(File.expand_path("#{ @config['locs']['berks'] }/cookbooks")) if File.exists?(File.expand_path("#{ @config['locs']['berks'] }/cookbooks"))
    
    Dir.chdir wrapper_cookbook_loc
    puts "Installing new cookbooks..."
    out = `berks install`
    puts "#{out}\nFinished fetching cookbooks, moving TheCheftacularCookbook into local chef repo"

    cheftacular_cookbook = @config['filesystem'].parse_latest_berkshelf_cookbook_versions.select {|key| key.include?('TheCheftacularCookbook')}['TheCheftacularCookbook']

    puts "Moving TheCheftacularCookbook (#{ cheftacular_cookbook['version'] })[#{ cheftacular_cookbook['mtime'] }] to your chef-repo!"

    `rm -Rf #{ @config['locs']['cookbooks'] }/TheCheftacularCookbook` if File.exists?(File.expand_path("#{ @config['locs']['cookbooks'] }/TheCheftacularCookbook"))
    `cp -Rf #{ @config['locs']['berks'] }/#{ cheftacular_cookbook['location'] } #{ @config['locs']['cookbooks'] }/TheCheftacularCookbook`

    break
  end
end

#update_tld(target_tld = "") ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/cheftacular/stateless_actions/update_tld.rb', line 17

def update_tld target_tld=""
  raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')
  
  raise "Undefined new tld to migrate to" if ARGV.length <= 1 && target_tld.blank? 

  nodes = @config['getter'].get_true_node_objects(true)

  #We need to manually update beta nodes as they share the same env space as their non-beta counterparts TODO Refactor?
  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: { env: @options['env'] }}] )

  address_hash = @config['getter'].get_addresses_hash @options['env']

  target_tld = ARGV[1] if target_tld.blank?

  old_tld = @config[@options['env']]['config_bag_hash'][@options['sub_env']]['tld']

  target_tld = old_tld if target_tld == 'self'

  nodes.each do |n|

    @options['node_name'] = n.name

    domain_obj = PublicSuffix.parse address_hash[n.public_ipaddress]['dn']

    next unless domain_obj.domain == old_tld #we can't create records for domains not managed under the environment's tld

    #TODO CHECK CLOUD IF TLD EXISTS

    specific_domain = "#{ domain_obj.trd }.#{ target_tld }"

    if specific_domain != "#{ @options['node_name'] }.#{ target_tld }"
      @config['DNS'].create_dns_record_for_domain_from_address_hash(specific_domain, address_hash[n.public_ipaddress], "specific_domain_mode")
    end

    @config['DNS'].create_dns_record_for_domain_from_address_hash(target_tld, address_hash[n.public_ipaddress])

    @config['DNS'].compile_address_hash_for_server_from_options("set_specific_domain_name:#{ specific_domain }")

    sleep 1 #prepare for next domain
  end

  @config[@options['env']]['config_bag_hash'][@options['sub_env']]['tld'] = target_tld

  @config['ChefDataBag'].save_config_bag
  @config['ChefDataBag'].save_addresses_bag
end

#upload_nodes(invalidate_file_node_cache = false) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/cheftacular/stateless_actions/upload_nodes.rb', line 30

def upload_nodes invalidate_file_node_cache=false
  @config['filesystem'].cleanup_file_caches('current-nodes') if invalidate_file_node_cache

  raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']

  @config['chef_environments'].each do |env|
    @config['initializer'].initialize_data_bags_for_environment env, false, ['node_roles']

    @config['initializer'].initialize_node_roles_bag_contents env
  end

  nodes = @options['multi-step'] ? @config['getter'].get_true_node_objects(true,true) : @config['getter'].get_true_node_objects(true)

  node_roles_hash, bag_hash, allowed_changes_hash = {},{},{}

  Dir.foreach(@config['locs']['nodes']) do |fr|
    next if @config['filesystem'].is_junk_filename?(fr)

    Dir.foreach("#{ @config['locs']['nodes'] }/#{ fr }") do |f|
      next if @config['filesystem'].is_junk_filename?(f)

      node_roles_hash[f.split('.json').first] = JSON.parse(File.read("#{ @config['locs']['nodes'] }/#{ fr }/#{ f }"))
    end
  end if @config['helper'].running_in_mode?('devops') #only devops modes should have a nodes_dir

  @config['chef_environments'].each do |env|
    @config[env]['node_roles_bag_hash']['node_roles'].each_pair do |role_name, role_hash|
      bag_hash[role_hash['name']] = role_hash.to_hash #hashes from chef server are stored as hashie objects until forced into hashes
    end
  end

  if !@options['force_yes'] && @config['helper'].running_in_mode?('devops') 
    node_roles_hash.each_pair do |role_name, role_hash|
      overwrite = false
      if bag_hash[role_name] != role_hash
        puts "Detected difference between saved roles hash and updated node_roles json hash for #{ role_name }."

        puts "Saved roles hash:"
        ap(bag_hash[role_name])

        puts "New roles hash:"
        ap(role_hash)

        puts "Preparing to overwrite the saved roles hash with the node_roles hash, enter Y/y to confirm."

        input = STDIN.gets.chomp

        overwrite = true if ( input =~ /y|Y|yes|Yes/ ) == 0

        allowed_changes_hash[role_name] = role_hash if overwrite
      else #bag_hash does not have a key for that role, populate it.
        allowed_changes_hash[role_name] = role_hash
      end

      @config[role_hash['chef_environment']]['node_roles_bag_hash']['node_roles'][role_name] = role_hash
    end
  else
    allowed_changes_hash = bag_hash
  end

  #force add any roles that are not in the bag in the event force yes is turned on
  (node_roles_hash.keys - bag_hash.keys).each do |role_not_in_node_roles_bag|

    new_role = node_roles_hash[role_not_in_node_roles_bag]

    allowed_changes_hash[role_not_in_node_roles_bag] = bag_hash[role_not_in_node_roles_bag]

    @config[new_role['chef_environment']]['node_roles_bag_hash']['node_roles'][new_role['name']] = new_role
  end if @options['force_yes'] && @config['helper'].running_in_mode?('devops')

  nodes.each do |node|
    # if there is a node_roles file that completely matches the name of the file, use it
    changes_for_current_node = false

    if allowed_changes_hash[node.name]
      allowed_changes_hash[node.name].each_pair do |node_key, node_val|
        if (node_key =~ /name/) != 0 && node.send(node_key) != node_val
          puts("Updating #{ node.name } with attribute #{ node_key } = #{ node_val } from #{ node.name }.json") unless @options['quiet']

          node.send("#{ node_key }=", node_val)

          changes_for_current_node, invalidate_file_node_cache = true, true
        end
      end

    elsif allowed_changes_hash.keys.include?(node.name.gsub(/\d/,'')) #if there is a template file that matches the stripped down name, use it
      allowed_changes_hash[node.name.gsub(/\d/,'')].each_pair do |node_key, node_val|
        if (node_key =~ /name/) != 0 && node.send(node_key) != node_val
          puts("Updating #{ node.name } with attribute #{ node_key } = #{ node_val } from template json file") unless @options['quiet']
          
          node.send("#{ node_key }=", node_val)

          changes_for_current_node, invalidate_file_node_cache = true, true
        end
      end
    end

    node.save if changes_for_current_node
  end

  @config['chef_environments'].each do |env|
    @config['ChefDataBag'].save_node_roles_bag env
  end if !@options['force_yes'] && @config['helper'].running_in_mode?('devops')

  @config['filesystem'].cleanup_file_caches('current-nodes') if invalidate_file_node_cache
end

#upload_rolesObject



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/cheftacular/stateless_actions/upload_roles.rb', line 15

def upload_roles
  raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']

  Dir.foreach(@config['locs']['roles']) do |rd|
    next if @config['filesystem'].is_junk_filename?(rd)

    puts("Loading in role from file #{ rd }") if @options['verbose']

    puts `knife role from file "#{ @config['locs']['roles'] }/#{ rd }"` 
  end
end

#vyatta_bootstrap(out = []) ⇒ Object



3
4
5
# File 'lib/cheftacular/stateless_actions/bootstrappers/vyatta_bootstrap.rb', line 3

def vyatta_bootstrap out=[]
  raise "Not yet implemented!"
end