Class: AppRb::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/app-rb/command.rb

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Command

Returns a new instance of Command.



3
4
5
# File 'lib/app-rb/command.rb', line 3

def initialize(config)
  @config = config
end

Instance Method Details

#cdObject



172
173
174
175
176
177
# File 'lib/app-rb/command.rb', line 172

def cd
  hash = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "hash")
  raise "FATAL: app is not started?" if hash == ""
  run_nodes = @config.nodes(@config.run["constraint"])
  AppRb::Util.do_it "ssh -t #{@config.user}@#{run_nodes.sample.ip} bash --login"
end

#cleanObject



152
153
154
155
156
# File 'lib/app-rb/command.rb', line 152

def clean
  base = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "base")
  ips = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "nodes").split(",")
  stop_services(ips, base)
end

#deploy(target) ⇒ Object



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
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
# File 'lib/app-rb/command.rb', line 7

def deploy(target)
  @base = "#{@config.app}-#{Time.now.to_i}"
  start_at = Time.now
  user = AppRb::Util.just_cmd("git config user.name")

  # init
  current_hash = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "hash")
  build_nodes = @config.nodes(@config.image["constraint"])
  if build_nodes.empty?
    puts "FATAL ERROR: no build nodes found"
    exit -1
  end
  pre_payloads = @config.pre_deploy.map do |pre|
    payload = {
      "nodes" => @config.nodes(pre["constraint"]),
      "cmd" => pre["cmd"],
      "opts" => pre["opts"] || [],
    }
    if payload["nodes"].empty?
      puts "FATAL ERROR: no pre deploy nodes found"
      exit -1
    end
    payload
  end
  deploy_payloads = @config.deploy.map { |key, section|
    nodes = @config.nodes(section["constraint"])
    if nodes.empty?
      puts "FATAL ERROR: no deploy `#{key}` nodes found"
      exit -1
    end
    {
      "key" => key,
      "nodes" => nodes,
      "amount" => (section["per"] ? section["per"]*nodes.count : section["amount"]),
      "cmd" => section["cmd"],
      "port" => section["port"],
      "check_url" => section["check_url"],
      "opts" => section["opts"] || [],
    }
  }
  if @config.run["constraint"]
    run_nodes = @config.nodes(@config.run["constraint"])
  else
    run_nodes = deploy_payloads.flat_map { |payload| payload["nodes"] }.uniq
  end
  if run_nodes.empty?
    puts "FATAL ERROR: no run nodes found"
    exit -1
  end
  cron_payloads = @config.cron.map { |key, section|
    nodes = @config.nodes(section["constraint"])
    if nodes.empty?
      puts "FATAL ERROR: no cron `#{key}` nodes found"
      exit -1
    end
    {
      "key" => key,
      "nodes" => nodes,
      "cmd" => section["cmd"],
      "at" => "#{section["minute"] || "*"} #{section["hour"] || "*"} #{section["day"] || "*"} #{section["month"] || "*"} #{section["weekday"] || "*"}"
    }
  }
  old_ips = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "nodes").split(",")
  new_ips = (
    build_nodes.map(&:ip) +
    pre_payloads.flat_map { |p| p["nodes"].map(&:ip) } +
    deploy_payloads.flat_map { |p| p["nodes"].map(&:ip) } +
    run_nodes.map(&:ip) +
    cron_payloads.flat_map { |p| p["nodes"].map(&:ip) }
  ).uniq
  ips = (old_ips + new_ips).uniq
  AppRb::Util::Consul.kv_set(@config.consul, @config.app, "nodes", ips.join(","))

  # pre
  new_hash = prepare_image(build_nodes, target)
  if @config.slack?
    notify_slack(@config.slack_url, @config.slack_channel, "#{user} start deploy *#{@config.app}* - https://github.com/#{@config.image["repo"]}/compare/#{current_hash.to_s[0..6]}...#{new_hash.to_s[0..6]}")
  end
  pre_deploy(pre_payloads, new_hash)
  stop_bg_jobs(ips)

  # deploy
  do_deploy(deploy_payloads, new_hash)

  # switch
  blue_green(deploy_payloads, new_hash)

  # update one time scripts
  one_time_scripts(run_nodes, ips, new_hash)

  # update crons
  set_crons(cron_payloads, ips, new_hash)

  # clean
  stop_services(ips)
  clean_registry(current_hash, [current_hash, new_hash].uniq)
  remove_old_images(ips, [current_hash, new_hash].uniq)

  # finish
  AppRb::Util::Consul.kv_set(@config.consul, @config.app, "nodes", new_ips.join(","))

  if @config.slack?
    notify_slack(@config.slack_url, @config.slack_channel, "#{user} finish deploy *#{@config.app}* :cat: :cat: :cat: - #{((Time.now.to_f - start_at.to_f)/60).round(1)} minutes")
  end

  puts AppRb::Util.green("Done.")
  if current_hash != "" && !target && current_hash != target
    puts "to rollback fire: app-rb #{ARGV[0]} deploy #{current_hash}"
  end
end

#redeployObject



158
159
160
161
162
163
# File 'lib/app-rb/command.rb', line 158

def redeploy
  hash = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "hash")
  raise "FATAL: app is not started?" if hash == ""
  puts "hash=#{hash}"
  deploy(hash)
end

#run(cmd) ⇒ Object



165
166
167
168
169
170
# File 'lib/app-rb/command.rb', line 165

def run(cmd)
  hash = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "hash")
  raise "FATAL: app is not started?" if hash == ""
  run_nodes = @config.nodes(@config.run["constraint"])
  AppRb::Util::Docker.run(@config.user, run_nodes.sample.ip, "#{@config.registry}/#{@config.app}:#{hash}", @config.env, cmd)
end

#statusObject



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
# File 'lib/app-rb/command.rb', line 118

def status
  ips = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "nodes").split(",")
  nodes = @config.nodes.select { |n| ips.index(n.ip) }
  max_name_len = nodes.map { |n| n.name.length }.max
  max_ip_len = nodes.map { |n| n.ip.length }.max
  current_base = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "base")
  current_hash = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "hash")
  current_dockers = nodes.map { |n| 
    AppRb::Util::Docker.ids(@config.user, n.ip, {app: @config.app, build: current_base}).count
  }
  dockers = nodes.map { |n| 
    AppRb::Util::Docker.ids(@config.user, n.ip, {app: @config.app}).count
  }
  puts ""
  puts AppRb::Util.green("App:     ") + @config.app
  puts AppRb::Util.green("Base:    ") + current_base
  puts AppRb::Util.green("Hash:    ") + current_hash
  nodes.each_with_index do |n, i|
    puts(
      " "*5 + n.name.rjust(max_name_len) + 
      " "*2 + n.ip.ljust(max_ip_len) + 
      " "*2 + AppRb::Util.green(current_dockers[i]) + " / " + (dockers[i] - current_dockers[i] == 0 ? "0" : AppRb::Util.red(dockers[i] - current_dockers[i]))
    )
    end
end

#stopObject



144
145
146
147
148
149
150
# File 'lib/app-rb/command.rb', line 144

def stop
  ips = AppRb::Util::Consul.kv_get(@config.consul, @config.app, "nodes").split(",")
  stop_all(ips)
  ips.each do |ip|
    AppRb::Util::Docker.add_cron(@config.user, ip, "#{@config.registry}/#{@config.app}:#{hash}", @config.env, @config.app, [])
  end
end