Class: EY::Enzyme::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/ey_enzyme/cli.rb

Constant Summary collapse

IGNORABLE_EXCEPTIONS =
[NoMemoryError, SignalException, Interrupt, SystemExit]
MAIN_RECIPE_PATH =
'/etc/chef/recipes'
CUSTOM_RECIPE_PATH =
'/etc/chef-custom/recipes'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ CLI

Returns a new instance of CLI.



81
82
83
84
85
86
87
# File 'lib/ey_enzyme/cli.rb', line 81

def initialize(opts={})
  @opts   = opts
  @api    = API.new(opts[:api], opts[:instance_id], opts[:token], opts[:logfile])
  @logger = MultiLogger.new(opts[:logfile])

  @opts[:timestamp] = Time.now.strftime("%Y-%m-%dT%H-%M-%S")
end

Class Method Details

.run(args) ⇒ Object



5
6
7
8
9
10
11
12
13
14
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
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
# File 'lib/ey_enzyme/cli.rb', line 5

def self.run(args)
  $stdout.sync = true

  defaults = {:config => '/etc/engineyard/dracul.yml', :keep => 5, :chef_bin => 'chef-solo',
              :logfile => "/var/log/enzyme.log"}
  options = {}

  opts = OptionParser.new do |opts|
    opts.version = EY::Enzyme::VERSION
    opts.banner = "Usage: ey-enzyme [-flag] [argument]"
    opts.define_head "ey-enzyme: running recipes..."
    opts.separator '*'*80

    opts.on("--quick", "Set the recipes to run in quick mode") do
      options[:quick] = true
    end

    opts.on("--logfile", "Set the logfile (defaults to /var/log/enzyme.log)") do |path|
      options[:logfile] = path
    end

    opts.on("--config CONFIG", "Use config file") do |config|
      options[:config] = config
    end

    opts.on("--chef-bin PATH", "Use this chef-solo executable to run recipes") do |binary|
      options[:chef_bin] = binary
    end

    opts.on("--main", "Run main recipes") do
      options[:type] = :main
    end

    opts.on("--custom", "Run custom recipes") do
      options[:type] = :custom
    end

    opts.on("--report message", "Report a status") do |message|
      options[:report] = true
      options[:message] = message
    end
  end

  opts.parse!(args)

  config = options[:config] || defaults[:config]
  cli    = new(defaults.merge(YAML.load_file(config)).merge(options))

  if options[:report]
    cli.report(options[:message])
  elsif options[:type]
    cli.deploy
  else
    abort opts.to_s
  end


rescue OptionParser::InvalidOption
  $stderr.puts "#{File.basename($0)} #{$!.message}"
  abort opts.to_s
rescue *IGNORABLE_EXCEPTIONS
  raise
rescue DeployError
  if cli
    cli.notify_user_error($!)
    exit 0
  end
  raise
rescue Exception
  if cli
    cli.notify_system_error($!)
    exit 0
  end
  raise
end

Instance Method Details

#deployObject



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/ey_enzyme/cli.rb', line 104

def deploy
  @logger.info "Starting configuration run"

  json = update_dna

  case @opts[:type]
  when :main
    run_main
    run_custom(json)
  when :custom
    run_custom(json)
  else
    raise "Unknown type: #{@opts[:type].inspect}"
  end

  @api.notify_success
end

#main_cookbooksObject



137
138
139
# File 'lib/ey_enzyme/cli.rb', line 137

def main_cookbooks
  @main_cookbooks ||= CookbookSet.new(@opts, "main", MAIN_RECIPE_PATH, @opts[:recipes_url], @api)
end

#notify_system_error(error) ⇒ Object



93
94
95
# File 'lib/ey_enzyme/cli.rb', line 93

def notify_system_error(error)
  @api.notify_error("system", error)
end

#notify_user_error(error) ⇒ Object



97
98
99
# File 'lib/ey_enzyme/cli.rb', line 97

def notify_user_error(error)
  @api.notify_error("user", error)
end

#report(message) ⇒ Object



89
90
91
# File 'lib/ey_enzyme/cli.rb', line 89

def report(message)
  @api.report(message)
end

#run_custom(json) ⇒ Object



127
128
129
130
131
132
133
134
135
# File 'lib/ey_enzyme/cli.rb', line 127

def run_custom(json)
  report 'running custom recipes if they exist'
  url = @opts.has_key?(:custom_recipes_url) ? @opts[:custom_recipes_url] : @api.custom_recipe_url
  update_custom_dna(json) if url

  @custom_cookbooks ||= CookbookSet.new(@opts, "custom", CUSTOM_RECIPE_PATH, url, @api)

  @custom_cookbooks.run
end

#run_mainObject



122
123
124
125
# File 'lib/ey_enzyme/cli.rb', line 122

def run_main
  report 'running main recipes'
  main_cookbooks.run
end

#update_chef_dna(file, json) ⇒ Object



168
169
170
171
172
173
# File 'lib/ey_enzyme/cli.rb', line 168

def update_chef_dna(file, json)
  File.open(file, 'w') do |f|
    f.puts JSON.pretty_generate(json)
    f.chmod(0600)
  end
end

#update_custom_dna(json) ⇒ Object



160
161
162
163
164
165
166
# File 'lib/ey_enzyme/cli.rb', line 160

def update_custom_dna(json)
  custom_json = json.dup
  custom_json['run_list'] = 'recipe[main]'
  # Make sure the path exist, it's soooo wrong to write this file before the cookbooks have been downloaded nor the config written
  FileUtils.mkdir_p('/etc/chef-custom/') unless File.exists?('/etc/chef-custom/')
  update_chef_dna("/etc/chef-custom/dna.json", custom_json)
end

#update_dnaObject



141
142
143
144
145
146
147
148
149
150
151
# File 'lib/ey_enzyme/cli.rb', line 141

def update_dna
  @logger.debug "Getting instance's DNA"

  unless json = @api.dna
    raise DNAError, "failed to fetch DNA"
  end

  @logger.debug "Writing json dna to file system"
  update_main_dna(json)
  json
end

#update_main_dna(json) ⇒ Object



153
154
155
156
157
158
# File 'lib/ey_enzyme/cli.rb', line 153

def update_main_dna(json)
  main_json = json.dup
  main_json['run_list'] = 'recipe[ey-base]'
  main_json["quick"] = true if @opts[:quick]
  update_chef_dna("/etc/chef/dna.json", main_json)
end