module NexClient::Commands::Apps

Constants

APPS_HEADERS
APPS_TITLE
OPTS_HEADERS
OPTS_TITLE
SCALING_DIRECTIONS
SCM_HEADERS
SCM_TITLE

Public Class Methods

create(args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 126
def self.create(args,opts)
  image_info = args.first.split(':')
  attrs = { image: image_info[0], image_tag: image_info[1] }

  # Meta attributes
  attrs[:ssl_enabled] = !opts.no_ssl if opts.no_ssl.present?
  attrs[:persistent_storage] = opts.storage if opts.storage.present?
  attrs[:container_size] = opts.size if opts.size.present?
  attrs[:description] = opts.desc if opts.desc.present?
  attrs[:tag_list] = opts.tags if opts.tags.present?
  attrs[:preferred_region] = opts.region if opts.region.present?

  # Additional options (log drain, region balancing)
  attrs[:opts] = self.extract_config_options(opts)

  # Env variables via command line
  if opts.env.present?
    attrs[:vars] ||= {}
    opts.env.each do |e|
      key,val = e.split('=',2)
      attrs[:vars][key] = val
    end
  end

  # Env variables from file
  if opts.env_file.present?
    attrs[:vars] ||= {}
    vars_from_file(opts.env_file) do |key,val|
      attrs[:vars][key] = val
    end
  end

  # Create the app
  e = NexClient::App.new(attrs)

  # Add owner if specified
  if opts.owner.present?
    o = NexClient::Organization.find(handle:opts.owner).first
    unless o
      error("Error! Could not find organization: #{opts.owner}")
      return false
    end
    e.relationships.attributes = { owner: { data: { type: o.type, id: o.id } } }
  end

  # Save the resource
  e.save

  # Display errors if any
  if e.errors.any?
    self.display_record_errors(e)
    return false
  end

  # Display app
  self.display_apps(NexClient::App.includes(:owner).find(e.id).first)
end
destroy(args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 225
def self.destroy(args,opts)
  name = args.first
  e = NexClient::App.find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Ask confirmation
  answer = ask("Enter the name of this app to confirm: ")
  unless answer == e.name
    error("Aborting deletion...")
    return false
  end

  e.destroy
  success("Successfully destroyed app: #{name}")
end
display_apps(list) click to toggle source
# File lib/nex_client/commands/apps.rb, line 434
def self.display_apps(list)
  table = Terminal::Table.new title: APPS_TITLE, headings: APPS_HEADERS do |t|
    [list].flatten.compact.each do |e|
      t.add_row(self.format_record(e))
    end
  end
  puts table
  puts "\n"
end
display_id(e) click to toggle source
# File lib/nex_client/commands/apps.rb, line 426
def self.display_id(e)
  table = Terminal::Table.new do |t|
    t.add_row(['APP ID',e.id])
  end
  puts table
  puts "\n"
end
display_options(list) click to toggle source
# File lib/nex_client/commands/apps.rb, line 444
def self.display_options(list)
  table = Terminal::Table.new title: OPTS_TITLE, headings: OPTS_HEADERS, style: { all_separators: true} do |t|
    [list].flatten.compact.each do |e|
      e.each do |k,v|
        val = v.is_a?(Hash) ? JSON.pretty_generate(v) : v
        t.add_row([k,val])
      end
    end
  end
  puts table
  puts "\n"
end
display_scm(list) click to toggle source
# File lib/nex_client/commands/apps.rb, line 457
def self.display_scm(list)
  table = Terminal::Table.new title: SCM_TITLE, headings: SCM_HEADERS do |t|
    [list].flatten.compact.each do |e|
      t.add_row(['provider',e['provider']])
      t.add_row(['repo',e['repo']])
      t.add_row(['branch',e['branch']])
      t.add_row(['last_commit',e['last_commit'] || '- nothing pushed yet -'])
      t.add_row(['webhook',e['webhook_enabled'].to_s == 'true' ? e['webhook_url'] : '- Not enabled -'])
    end
  end
  puts table
  puts "\n"
end
extract_config_options(cli_opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 499
def self.extract_config_options(cli_opts)
  hash = {}
  %w(http_log_drain region_balancing).each do |opt_name|
    if cli_opts.method_missing(opt_name.to_sym).present?
      hash[opt_name.to_s] = cli_opts.method_missing(opt_name.to_sym)
    end
  end
  return hash
end
format_node_count(record) click to toggle source
# File lib/nex_client/commands/apps.rb, line 494
def self.format_node_count(record)
  return '-' unless record.node_count && record.max_node_count
  "#{record.node_count}/#{record.max_node_count}"
end
format_owner(record) click to toggle source
# File lib/nex_client/commands/apps.rb, line 489
def self.format_owner(record)
  return '-' unless o = record.owner
  "#{o.type[0]}:#{o.handle}"
end
format_record(record) click to toggle source
# File lib/nex_client/commands/apps.rb, line 471
def self.format_record(record)
  owner = self.format_owner(record)
  node_count = self.format_node_count(record)
  [
    record.name,
    record.status,
    [record.image,record.image_tag].compact.join(':'),
    record.ssl_enabled,
    record.persistent_storage,
    record.preferred_region,
    record.container_size,
    node_count,
    owner,
    record.description,
    (record.tag_list || []).join(',')
  ]
end
info(args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 43
def self.info(args,opts)
  name = args.first
  e = NexClient::App.includes(:addons,:owner,:domains,:ssl_certificates, :cube_instances).find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Display app id
  self.display_id(e)

  # Display app details
  self.display_apps(e)

  # Display all vars
  self.display_vars(e.all_vars,!opts.full_vars)

  # Display options
  self.display_options(e.opts) if e.respond_to?(:opts)

  # Display Source Control Management
  self.display_scm(e.scm)

  # Display custom domains
  Domains.display_domains(e.domains)

  # Display SSL certificates
  SslCertificates.display_certs(e.ssl_certificates)

  # Display all addons
  Addons.display_addons(e.addons.select { |a| a.status == 'active'})

  # Display Cubes
  CubeInstances.display_cubes(e.cube_instances)
end
list(args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 19
def self.list(args,opts)
  filters = {}
  filters[:status] = opts.status || ['active','restarting']
  filters[:ssl_enabled] = opts.ssl if opts.ssl.present?
  filters[:persistent_storage] = opts.storage if opts.storage.present?
  filters[:'owner.handle'] = opts.owner if opts.owner.present?
  filters[:image] = opts.image if opts.image.present?
  filters[:tags] = opts.tags if opts.tags.present?

  # All option
  filters = {} if opts.all

  # Display
  list = NexClient::App.includes(:owner).where(filters).order('status')
  self.display_apps(list)

  # Loop through results
  while (list.pages.links||{})['next']
    return true if ask("Press enter for next page ('q' to quit)") =~ /q/
    list = list.pages.next
    self.display_apps(list)
  end
end
logs(args,opts) click to toggle source

Retrieve application logs from all containers

# File lib/nex_client/commands/apps.rb, line 96
def self.logs(args,opts)
  name = args.first
  e = NexClient::App.find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Retrieve logs and display them
  logs = e.logs(tail: opts.tail).first
  self.display_logs(logs.log_ret)
end
manage_scm(args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 387
def self.manage_scm(args,opts)
  name = args.first
  e = NexClient::App.find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Link SCM
  if opts.link
    provider,repo,branch = opts.link.split(':')
    credentials = opts.credentials
    attrs = {
      provider: provider,
      config: {
        repo: repo,
        branch: branch,
        credentials: credentials
      }
    }

    # Update and reload the resource
    e.link_scm({data: { attributes: attrs } })
    e = NexClient::App.find(e.id).first
  end

  # Unlink SCM
  if !opts.link && opts.unlink
    # Update and reload the resource
    e.unlink_scm
    e = NexClient::App.find(e.id).first
  end

  # Display SCM
  self.display_scm(e.scm)
end
manage_vars(args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 331
def self.manage_vars(args,opts)
  name = args.first
  e = NexClient::App.find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Add/Delete vars
  if opts.add.present? || opts.delete.present? || opts.env_file.present?
    vars = (e.vars || {}).dup

    # Add vars
    (opts.add || []).each do |v|
      key,val = v.split('=',2)
      vars[key] = val
    end

    # Add vars from file
    if opts.env_file.present?
      vars_from_file(opts.env_file,opts.env_prefix) do |key,val|
        vars[key] = val
      end
    end

    # Delete vars
    (opts.delete || []).each { |k| vars.delete(k) }
    # Delete all vars
    if opts.delete_all
      # Ask confirmation
      answer = ask('Enter the name of this app to confirm: ')
      unless answer == e.name
        error('Aborting vars deletion')
        return false
      end
      vars = {}
    end

    # Update and reload the resource
    e.update_attributes(vars: vars)
    e = NexClient::App.find(e.id).first
    success("Successfully updated env vars. You may want to restart your app...")
  end

  # Display all vars
  if opts.yaml
    self.display_yaml_vars(e.all_vars)
  elsif opts.raw
    self.display_raw_vars(e.all_vars)
  else
    self.display_vars(e.all_vars,!opts.full_vars)
  end
end
open(args,opts) click to toggle source

Open application in Browser

# File lib/nex_client/commands/apps.rb, line 82
def self.open(args,opts)
  name = args.first
  app = NexClient::App.includes(:domains).find(name: name).first
  # Display error
  unless app
    error("Error! Could not find app: #{name}")
    return false
  end
  url = app.preferred_url
  success "Opening #{url}"
  Launchy.open(url)
end
restart(args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 280
def self.restart(args,opts)
  name = args.first
  e = NexClient::App.find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Perform
  e.restart

  # Display errors if any
  if e.errors.any?
    display_record_errors(e)
    return false
  end

  success("Initiated phased restart for app: #{name}...")
end
scale(direction,args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 302
def self.scale(direction,args,opts)
  return false unless SCALING_DIRECTIONS.include?(direction.to_sym)
  name = args.first
  e = NexClient::App.find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Scaling attributes
  attrs = {}
  count = opts.count || 1
  attrs[:count] = count
  attrs[:preferred_region] = opts.region if opts.region.present?

  # Perform
  e.send("scale_#{direction}",{data: { attributes: attrs } })

  # Display errors if any
  if e.errors.any?
    display_record_errors(e)
    return false
  end

  success("Successfully requested to scale #{name} #{direction} by #{count} #{'node'.pluralize(count)}...")
end
ssh(args,opts) click to toggle source

SSH to the app

# File lib/nex_client/commands/apps.rb, line 112
def self.ssh(args,opts)
  name = args.first
  e = NexClient::App.find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Perform command
  perform_ssh_cmd(e.ssh_cmd_template)
end
transfer(args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 246
def self.transfer(args,opts)
  name = args.first
  e = NexClient::App.find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Get owner
  handle = args.last
  o = NexClient::Organization.find(handle: handle).first ||
    NexClient::User.find(handle: handle).first

  # Display error if owner not found
  unless o
    error("Error! Could not find owner: #{handle}")
    return false
  end

  # Update and save record
  e.relationships.attributes = { owner: { data: { type: o.type, id: o.id } } }
  e.save

  # Display errors if any
  if e.errors.any?
    display_record_errors(e)
    return false
  end

  success("Successfully transfered #{name} to #{handle}")
end
update(args,opts) click to toggle source
# File lib/nex_client/commands/apps.rb, line 184
def self.update(args,opts)
  name = args.first
  e = NexClient::App.find(name: name).first

  # Display error
  unless e
    error("Error! Could not find app: #{name}")
    return false
  end

  # Attributes
  attrs = {}
  attrs[:container_size] = opts.size if opts.size.present?
  attrs[:description] = opts.desc if opts.desc.present?
  attrs[:tag_list] = opts.tags if opts.tags.present?
  attrs[:image_tag] = opts.image_tag if opts.image_tag.present?
  attrs[:preferred_region] = opts.region if opts.region.present?

  # Additional options (log drain, region balancing)
  # Hash#dup is required for the resource to detect changes
  attrs[:opts] = (e.opts || {}).dup.merge(self.extract_config_options(opts))

  if opts.waf_rules
    waf_rules = begin
      if opts.waf_rules.is_a?(String)
        hash_from_file(opts.waf_rules)
      else
        val = ask("Copy/paste your WAF configuration below in JSON format:") { |q| q.gather = "" }
        JSON.parse(val.join(""))
      end
    end
    attrs[:opts]['waf_rules'] = waf_rules
  end

  # Update
  e.update_attributes(attrs)

  # Display app
  self.display_apps(NexClient::App.includes(:owner).find(e.id).first)
end