class Mamiya::CLI::Client

Public Instance Methods

deploy(package) click to toggle source
# File lib/mamiya/cli/client.rb, line 180
def deploy(package)
  deploy_or_rollback(:deploy, package)
end
distribute(package) click to toggle source
# File lib/mamiya/cli/client.rb, line 146
def distribute(package)
  params = options[:labels] ?
    {labels: Mamiya::Util::LabelMatcher.parse_string_expr(options[:labels])} : {}

  p master_post("/packages/#{application}/#{package}/distribute", params.merge(type: :json))
end
join(host) click to toggle source
# File lib/mamiya/cli/client.rb, line 202
def join(host)
  master_post('/join', host: host)
end
list_agents() click to toggle source
# File lib/mamiya/cli/client.rb, line 48
def list_agents
  params = options[:labels] ? {labels: options[:labels]} : {}
  payload = master_get("/agents", params)

  agents = payload["agents"].keys

  agents.each do |agent|
    puts "#{agent}\talive"
  end
  payload["failed_agents"].each do |agent|
    puts "#{agent}\tfailed"
  end
end
list_applications() click to toggle source
# File lib/mamiya/cli/client.rb, line 19
def list_applications
  puts master_get('/packages')["applications"]
end
list_packages() click to toggle source
# File lib/mamiya/cli/client.rb, line 24
def list_packages
  puts master_get("/packages/#{application}")["packages"]
end
prepare(package) click to toggle source
# File lib/mamiya/cli/client.rb, line 155
def prepare(package)
  params = options[:labels] ?
    {labels: Mamiya::Util::LabelMatcher.parse_string_expr(options[:labels])} : {}

  p master_post("/packages/#{application}/#{package}/prepare", params.merge(type: :json))
end
refresh() click to toggle source
# File lib/mamiya/cli/client.rb, line 170
def refresh
  p master_post('/agents/refresh')
end
rollback() click to toggle source
# File lib/mamiya/cli/client.rb, line 190
def rollback
  appstatus = master_get("/applications/#{application}/status", options[:labels] ? {labels: options[:labels]} : {})
  package = appstatus['common_previous_release']

  unless package
    raise 'there is no common_previous_release for specified application'
  end

  deploy_or_rollback(:rollback, package)
end
show_agent(agent) click to toggle source
# File lib/mamiya/cli/client.rb, line 64
def show_agent(agent)
  agent = master_get("/agents/#{agent}")

  case options[:format]
  when 'pp'
    require 'pp'
    pp agent
  when 'json'
    require 'json'
    puts agent.to_json
  when 'yaml'
    require 'yaml'
    puts agent.to_yaml
  end
end
show_distribution(package) click to toggle source
# File lib/mamiya/cli/client.rb, line 85
      def show_distribution(package)
        params = options[:labels] ? {labels: options[:labels]} : {}
        dist = master_get("/packages/#{application}/#{package}/distribution", params)

        case options[:format]
        when 'json'
          require 'json'
          puts dist.to_json
          return

        when 'yaml'
          require 'yaml'
          puts dist.to_yaml
          return
        end

        total = dist['distributed_count'] + dist['fetching_count'] +
          dist['queued_count'] + dist['not_distributed_count'] 

        progress = "%.1f" % ((dist['distributed_count']/total.to_f)*100)
        puts <<-EOF
package:         #{application}/#{package}
status:          #{dist['status']}
progress:        #{progress}

distributed:     #{dist['distributed_count']} agents
fetching:        #{dist['fetching_count']} agents
queued:          #{dist['queued_count']} agents
not distributed: #{dist['not_distributed_count']} agents
        EOF

        if options[:verbose]
          puts ""
          dist['distributed'].each do |name|
            puts "#{name}\tdistributed"
          end
          dist['queued'].each do |name|
            puts "#{name}\tqueued"
          end
          dist['not_distributed'].each do |name|
            puts "#{name}\tnot_distributed"
          end

        end
      end
show_package(package) click to toggle source
# File lib/mamiya/cli/client.rb, line 30
def show_package(package)
  meta = @meta =  master_get("/packages/#{application}/#{package}")

  case options[:format]
  when 'pp'
    require 'pp'
    pp meta
  when 'json'
    require 'json'
    puts meta.to_json
  when 'yaml'
    require 'yaml'
    puts meta.to_yaml
  end
end
status(package=nil) click to toggle source
# File lib/mamiya/cli/client.rb, line 135
def status(package=nil)
  if package
    pkg_status package
  else
    app_status
  end
end
switch(package) click to toggle source
# File lib/mamiya/cli/client.rb, line 165
def switch(package)
  switch_(package, no_release: options[:no_release])
end

Private Instance Methods

app_status() click to toggle source
# File lib/mamiya/cli/client.rb, line 366
      def app_status
        params = options[:labels] ? {labels: options[:labels]} : {}
        status = master_get("/applications/#{application}/status", params)

        case options[:format]
        when 'json'
          require 'json'
          puts status.to_json
          return

        when 'yaml'
          require 'yaml'
          puts status.to_yaml
          return

        end

        puts <<-EOF
at: #{Time.now.inspect}
application: #{application}
agents: #{status['agents_count']} agents
participants: #{status['participants_count']} agents

major_current: #{status['major_current']}
currents:
#{status['currents'].sort_by { |pkg, as| -(as.size) }.flat_map { |pkg, as|
["  - #{pkg} (#{as.size} agents)"] + (pkg == status['major_current'] ? [] : as.map{ |_| "    * #{_}" })
}.join("\n")}

common_previous_release: #{status['common_previous_release']}
common_releases:
#{status['common_releases'].map { |_| _.prepend('  - ') }.join("\n")}
        EOF

        if status['non_participants'] && !status['non_participants'].empty?
          puts "\nnon_participants:"
          status['non_participants'].each do |agent|
            puts "  * #{agent}"
          end
        end
      end
application() click to toggle source
# File lib/mamiya/cli/client.rb, line 213
def application
  @_application ||=
    ENV['MAMIYA_APP'] \
    || ENV['MAMIYA_APPLICATION'] \
    || options[:application] \
    or fatal!('specify application')
end
config() click to toggle source
# File lib/mamiya/cli/client.rb, line 221
def config
  return @config if @config
  path = [options[:config], './mamiya.conf.rb', './config.rb', '/etc/mamiya/config.rb'].compact.find { |_| File.exists?(_) }

  if path
    @config = Mamiya::Configuration.new.load!(File.expand_path(path))
  end

  @config
end
deploy_or_rollback(type, package) click to toggle source
# File lib/mamiya/cli/client.rb, line 272
def deploy_or_rollback(type, package)
  @deploy_exception = nil
  synced_release = options[:synced_release] || (config && config.synced_release)

  # TODO: move this run on master node side
  if type == :deploy
    puts "=> Deploying #{application}/#{package}"
  else
    puts "=> Rolling back #{application} to #{package}"
  end
  puts " * onto agents which labeled: #{options[:labels].inspect}" if options[:labels] && !options[:labels].empty?
  puts " * releasing will be synced in all agents" if synced_release

  show_package(package)

  if config
    config.set :deploy_options, options
    config.set :application, application
    config.set :package_name, package
    config.set :package, @meta

    config.before_deploy_or_rollback[]
    (type == :deploy ? config.before_deploy : config.before_rollback)[]
  end

  if type == :deploy
    do_prep = -> do
      puts " * sending prepare request"
      prepare(package)
    end

    puts "=> Wait agents to have prepared"
    puts ""

    i = 0
    loop do
      i += 1
      do_prep[] if i == 2 || i % 25 == 0

      s = pkg_status(package, :short)
      puts ""
      break if 0 < s['participants_count'] && s['non_participants'].empty? && s['participants_count'] == s['prepare']['done'].size
      sleep 2
    end
  end

  ###
  #

  unless options[:no_switch]
    puts "=> Switching..."
    switch_(package, no_release: synced_release)

    puts " * Wait until switch"
    puts ""
    loop do
      s = pkg_status(package, :short)
      puts ""
      break if s['participants_count'] == s['switch']['done'].size
      sleep 2
    end

    if synced_release
      puts "=> Releasing..."
      switch_(package, do_release: true)

      puts " * due to current implementation's limitation, releasing will be untracked."
    end
  end
rescue Exception => e
  @deploy_exception = e
  $stderr.puts "ERROR: #{e.inspect}"
  $stderr.puts "\t#{e.backtrace.join("\n\t")}"
ensure

  (type == :deploy ? config.after_deploy : config.after_rollback)[@deploy_exception] if config
  config.after_deploy_or_rollback[@deploy_exception] if config
  puts "=> Done."

end
fatal!(msg) click to toggle source
# File lib/mamiya/cli/client.rb, line 208
def fatal!(msg)
  $stderr.puts msg
  exit 1
end
master_get(path, params={}) click to toggle source
# File lib/mamiya/cli/client.rb, line 232
def master_get(path, params={})
  path += "?#{Rack::Utils.build_query(params)}" unless params.empty?
  master_http.start do |http|
    JSON.parse http.get(path).tap(&:value).body
  end
end
master_http() click to toggle source
# File lib/mamiya/cli/client.rb, line 353
def master_http
  url = master_url
  Net::HTTP.new(url.host, url.port).tap do |http|
    http.use_ssl = true if url.scheme == 'https'
  end
end
master_post(path, data='') click to toggle source
# File lib/mamiya/cli/client.rb, line 239
def master_post(path, data='')
  response = nil
  master_http.start do |http|
    headers = {}

    if Hash === data
      case data.delete(:type) || :query
      when :json
        data = data.to_json
        headers['Content-Type'] = 'application/json'
      when :query
        data = Rack::Utils.build_nested_query(data)
      end
    end

    response = http.post(path, data, headers)
    response.value
    response.code == '204' ? true : JSON.parse(response.body)
  end
rescue Net::HTTPExceptions => e
  puts response.body rescue nil
  raise e
end
master_url() click to toggle source
# File lib/mamiya/cli/client.rb, line 360
def master_url
  url = ENV["MAMIYA_MASTER_URL"] || options[:master]
  fatal! 'specify master URL via --master(-u) option or $MAMIYA_MASTER_URL' unless url
  URI.parse(url)
end
pkg_status(package, short=false) click to toggle source
# File lib/mamiya/cli/client.rb, line 408
      def pkg_status(package, short=false)
        params = options[:labels] ? {labels: options[:labels]} : {}
        status = master_get("/packages/#{application}/#{package}/status", params)

        case options[:format]
        when 'json'
          require 'json'
          puts status.to_json
          return

        when 'yaml'
          require 'yaml'
          puts status.to_yaml
          return

        end

        total = status['participants_count']

        if short
          puts "#{Time.now.strftime("%H:%M:%S")}  app:#{application} pkg:#{package}  agents:#{total}"
        else
          puts <<-EOF
at: #{Time.now.inspect}
package: #{application}/#{package}
status: #{status['status'].join(',')}

participants: #{total} agents

          EOF

          if status['non_participants'] && !status['non_participants'].empty?
            status['non_participants'].each do |agent|
              puts "  * #{agent}"
            end
            puts
          end
        end

          %w(fetch prepare switch).each do |key|
            status[key].tap do |st|
              puts "#{key}: queued=#{st['queued'].size}, working=#{st['working'].size}, done=#{st['done'].size}"
              puts "  * queued:  #{st['queued'].join(', ')}" if !st['queued'].empty? && st['queued'].size != total
              puts "  * working: #{st['working'].join(', ')}" if !st['working'].empty? && st['working'].size != total
              puts "  * done:    #{st['done'].join(', ')}" if !st['done'].empty? && options[:show_done] && st['done'].size != total
            end
          end

        status
      end
switch_(package, no_release: false, do_release: false) click to toggle source
# File lib/mamiya/cli/client.rb, line 263
def switch_(package, no_release: false, do_release: false)
  params = {no_release: no_release, do_release: do_release}
  if options[:labels]
    params[:labels] = Mamiya::Util::LabelMatcher.parse_string_expr(options[:labels])
  end

  p master_post("/packages/#{application}/#{package}/switch", params.merge(type: :json))
end