Class: Skytap::Commands::Download

Inherits:
Base
  • Object
show all
Defined in:
lib/skytap/plugins/vm_download.rb

Constant Summary collapse

MAX_CONCURRENCY =
5
CHECK_PERIOD =
15
AT_CAPACITY_RETRY_PERIOD =
15.minutes.to_i

Instance Attribute Summary collapse

Attributes inherited from Base

#args, #command_options, #error, #global_options, #invoker, #logger

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#api_token, #ask, #ask_param, #command_line_params, command_name, #composed_params, #file_params, #find_id, #initialize, #interactive_params, #invoke, make_from, #noninteractive_params, #programmatic?, #solicit_user_input?, #username

Methods included from Help

#description, #help!, #help?, included, #parameters, #synopsis, #version?

Constructor Details

This class inherits a constructor from Skytap::Commands::Base

Instance Attribute Details

#downloadersObject (readonly)

Returns the value of attribute downloaders.



9
10
11
# File 'lib/skytap/plugins/vm_download.rb', line 9

def downloaders
  @downloaders
end

#vm_idsObject (readonly)

Returns the value of attribute vm_ids.



8
9
10
# File 'lib/skytap/plugins/vm_download.rb', line 8

def vm_ids
  @vm_ids
end

Class Method Details

.descriptionObject



14
15
16
17
18
19
20
21
# File 'lib/skytap/plugins/vm_download.rb', line 14

def self.description
  <<-"EOF"
Download the specified Skytap template VM to the local filesystem

The VM must belong to a template, not a configuration. The template cannot be
public.
  EOF
end

Instance Method Details

#active_downloadersObject



151
152
153
# File 'lib/skytap/plugins/vm_download.rb', line 151

def active_downloaders
  downloaders.reject(&:finished?)
end

#concurrency_at_overageObject



58
59
60
# File 'lib/skytap/plugins/vm_download.rb', line 58

def concurrency_at_overage
  @concurrency_at_overage
end

#estimated_available_slotsObject



126
127
128
129
130
131
132
# File 'lib/skytap/plugins/vm_download.rb', line 126

def estimated_available_slots
  if full?
    0
  else
    MAX_CONCURRENCY - concurrency
  end
end

#expected_argsObject



23
24
25
26
27
# File 'lib/skytap/plugins/vm_download.rb', line 23

def expected_args
  ActiveSupport::OrderedHash[
    'vm_id*', 'One or more IDs of template VMs to donwload'
  ]
end

#expected_optionsObject



29
30
31
32
33
# File 'lib/skytap/plugins/vm_download.rb', line 29

def expected_options
  ActiveSupport::OrderedHash[
    :dir, {:flag_arg => 'DIR', :desc => 'Directory into which to download VM and metadata'},
  ]
end

#finished?Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/skytap/plugins/vm_download.rb', line 109

def finished?
  vm_ids.empty? && concurrency == 0
end

#full?Boolean

Returns:

  • (Boolean)


143
144
145
# File 'lib/skytap/plugins/vm_download.rb', line 143

def full?
  @full_at
end

#kick_off_export(vm_id) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/skytap/plugins/vm_download.rb', line 62

def kick_off_export(vm_id)
  begin
    # Create export job on server in main thread.
    job = VmExportJob.new(logger, username, api_token, vm_id, command_options[:dir])

    # If successful, start FTP download and subsequent steps in new thread.
    dl = Downloader.new(job)
    downloaders << dl
    log_line(dl.status_line)
  rescue NoSlotsAvailable => ex
    vm_ids << vm_id
    signal_full
    log_line(("VM #{vm_id}: " << no_capacity_message).color(:yellow))
  rescue Exception => ex
    dl = DeadDownloader.new(vm_id, ex)
    downloaders << dl
    log_line(dl.status_line)
  end
end

#log_line(msg, include_separator = true) ⇒ Object



93
94
95
96
97
# File 'lib/skytap/plugins/vm_download.rb', line 93

def log_line(msg, include_separator=true)
  line = msg
  line += "\n---" if include_separator
  logger.info line
end

#no_capacity_messageObject



82
83
84
85
86
87
88
89
90
91
# File 'lib/skytap/plugins/vm_download.rb', line 82

def no_capacity_message
  m = AT_CAPACITY_RETRY_PERIOD / 60
  "No export capacity is currently available on Skytap. Will retry in #{m} minutes".tap do |msg|
    if active_downloaders.present?
      msg << ' or when another export completes.'
    else
      msg << '.'
    end
  end
end


99
100
101
# File 'lib/skytap/plugins/vm_download.rb', line 99

def print_status
  logger.info "#{status_lines}\n---"
end


103
104
105
106
107
# File 'lib/skytap/plugins/vm_download.rb', line 103

def print_summary
  unless response.error?
    logger.info "#{'Summary'.bright}\n#{response.payload}"
  end
end

#run!Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/skytap/plugins/vm_download.rb', line 37

def run!
  @vm_ids = args.collect {|a| find_id(a)}
  @downloaders = []

  until finished?
    if vm_ids.present? && slots_available?
      kick_off_export(vm_ids.shift)
    else
      sleep CHECK_PERIOD
      print_status
      invoker.try(:call, self)

      signal_available if signal_stale? || (concurrency_at_overage && concurrency < concurrency_at_overage)
    end
  end

  signal_available
  print_summary
  return response
end

#seconds_until_retryObject



121
122
123
124
# File 'lib/skytap/plugins/vm_download.rb', line 121

def seconds_until_retry
  return unless full?
  [0, AT_CAPACITY_RETRY_PERIOD - (Time.now - @full_at)].max
end

#signal_availableObject



139
140
141
# File 'lib/skytap/plugins/vm_download.rb', line 139

def signal_available
  @concurrency_at_overage = @full_at = nil
end

#signal_fullObject



134
135
136
137
# File 'lib/skytap/plugins/vm_download.rb', line 134

def signal_full
  @concurrency_at_overage = concurrency
  @full_at = Time.now
end

#signal_stale?Boolean

Returns:

  • (Boolean)


117
118
119
# File 'lib/skytap/plugins/vm_download.rb', line 117

def signal_stale?
  full? && Time.now - @full_at > AT_CAPACITY_RETRY_PERIOD
end

#slots_available?Boolean

Returns:

  • (Boolean)


113
114
115
# File 'lib/skytap/plugins/vm_download.rb', line 113

def slots_available?
  estimated_available_slots > 0
end

#status_linesObject



147
148
149
# File 'lib/skytap/plugins/vm_download.rb', line 147

def status_lines
  active_downloaders.collect(&:status_line).join("\n")
end