Module: Spoon

Includes:
Methadone::CLILogging, Methadone::Main, Methadone::SH
Defined in:
lib/spoon.rb,
lib/spoon/version.rb

Constant Summary collapse

VERSION =
"0.3.0"

Class Method Summary collapse

Class Method Details

.apply_prefix(name) ⇒ Object



66
67
68
# File 'lib/spoon.rb', line 66

def self.apply_prefix(name)
  "spoon-#{name}"
end

.D(message) ⇒ Object



284
285
286
287
288
# File 'lib/spoon.rb', line 284

def self.D(message)
  if options[:debug]
    puts "D: #{message}"
  end
end

.docker_urlObject



276
277
278
# File 'lib/spoon.rb', line 276

def self.docker_url
  Docker.url = options[:url]
end

.get_all_containersObject



227
228
229
# File 'lib/spoon.rb', line 227

def self.get_all_containers
  Docker::Container.all(:all => true)
end

.get_container(name) ⇒ Object



239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/spoon.rb', line 239

def self.get_container(name)
  docker_url
  container_list = get_all_containers

  l_name = strip_slash(name)
  container_list.each do |container|
    if container.info["Names"].first.to_s == "/#{l_name}"
      return container
    end
  end
  return nil
end

.get_port(port, container) ⇒ Object



280
281
282
# File 'lib/spoon.rb', line 280

def self.get_port(port, container)
  container.json['NetworkSettings']['Ports']["#{port}/tcp"].first['HostPort']
end

.get_running_containersObject



231
232
233
# File 'lib/spoon.rb', line 231

def self.get_running_containers
  Docker::Container.all
end

.host_available?(hostname, port) ⇒ Boolean

Returns:

  • (Boolean)


263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/spoon.rb', line 263

def self.host_available?(hostname, port)
  socket = TCPSocket.new(hostname, port)
  IO.select([socket], nil, nil, 5)
rescue SocketError, Errno::ECONNREFUSED,
  Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
  sleep(0.25)
  false
rescue Errno::EPERM, Errno::ETIMEDOUT
  false
ensure
  socket && socket.close
end

.image_buildObject



78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/spoon.rb', line 78

def self.image_build
  # Run pre-build commands
  options["pre-build-commands"].each do |command|
    sh command
  end unless options["pre-build-commands"].nil?
  D "pre-build commands complete, building Docker image"

  docker_url
  build_opts = { 't' => options[:image], 'rm' => true }
  Docker::Image.build_from_dir(options[:builddir], build_opts) do |chunk|
    print_docker_response(chunk)
  end
end

.image_listObject



92
93
94
95
96
97
98
# File 'lib/spoon.rb', line 92

def self.image_list
  docker_url
  Docker::Image.all.each do |image|
    next if image.info["RepoTags"] == ["<none>:<none>"]
    puts "Image: #{image.info["RepoTags"]}"
  end
end

.instance_connect(name, command = '') ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/spoon.rb', line 122

def self.instance_connect(name, command='')
  docker_url
  if not instance_exists? name
    puts "The `#{name}` container doesn't exist, creating..."
    instance_create(name)
  end

  container = get_container(name)
  unless is_running?(container)
    instance_start(container)
  end

  puts "Connecting to `#{name}`"
  instance_ssh(name, command)
end

.instance_create(name) ⇒ Object



252
253
254
255
256
257
258
259
260
261
# File 'lib/spoon.rb', line 252

def self.instance_create(name)
  docker_url
  container = Docker::Container.create({
    'Image' => options[:image],
    'name' => name,
    'Entrypoint' => 'runit',
    'Hostname' => remove_prefix(name)
  })
  container = container.start({ 'PublishAllPorts' => true })
end

.instance_destroy(name) ⇒ Object



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/spoon.rb', line 185

def self.instance_destroy(name)
  docker_url
  container = get_container(name)

  if container
    puts "Destroying #{name}"
    begin
      container.kill
    rescue
      puts "Failed to kill container #{container.id}"
    end

    container.wait(10)

    begin
      container.delete(:force => true)
    rescue
      puts "Failed to remove container #{container.id}"
    end
    puts "Done!"
  else
    puts "No container named: #{name}"
  end
end

.instance_exists?(name) ⇒ Boolean

Returns:

  • (Boolean)


210
211
212
# File 'lib/spoon.rb', line 210

def self.instance_exists?(name)
  get_container(name)
end

.instance_listObject



138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/spoon.rb', line 138

def self.instance_list
  docker_url
  puts "List of available spoon containers:"
  container_list = get_all_containers
  container_list.each do |container|
    name = container.info["Names"].first.to_s
    if name.start_with? "/#{options[:prefix]}"
      running = is_running?(container) ? Rainbow("Running").green : Rainbow("Stopped").red
      puts "#{remove_prefix(name)} [ #{running} ]".rjust(40)
    end
  end
end

.instance_network(name) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/spoon.rb', line 169

def self.instance_network(name)
  docker_url

  container = get_container(name)

  if is_running?(container)
    ports = container.json['NetworkSettings']['Ports']
    ports.each do |p_name, p_port|
      tcp_name = p_name.split('/')[0]
      puts "#{tcp_name} -> #{p_port.first['HostPort']}"
    end
  else
    puts "Container is not running, cannot show ports"
  end
end

.instance_ssh(name, command = '') ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/spoon.rb', line 214

def self.instance_ssh(name, command='')
  container = get_container(name)
  host = URI.parse(options[:url]).host
  if container
    ssh_command = "\"#{command}\"" if not command.empty?
    ssh_port = get_port('22', container)
    puts "Waiting for #{name}:#{ssh_port}..." until host_available?(host, ssh_port)
    exec("ssh -t -o StrictHostKeyChecking=no -p #{ssh_port} pairing@#{host} #{ssh_command}")
  else
    puts "No container named: #{container.inspect}"
  end
end

.instance_start(container) ⇒ Object



235
236
237
# File 'lib/spoon.rb', line 235

def self.instance_start(container)
  container.start!
end

.is_running?(container) ⇒ Boolean

Returns:

  • (Boolean)


159
160
161
162
163
164
165
166
167
# File 'lib/spoon.rb', line 159

def self.is_running?(container)
  container = Docker::Container.get(container.info["id"])
  status = container.info["State"]["Running"] || nil
  unless status.nil?
    return status
  else
    return false
  end
end

.parse_config(config_file) ⇒ Object



62
63
64
# File 'lib/spoon.rb', line 62

def self.parse_config(config_file)
  eval(File.open(config_file).read)
end


118
119
120
# File 'lib/spoon.rb', line 118

def self.print_docker_response(json)
  print_parsed_response(JSON.parse(json))
end


100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/spoon.rb', line 100

def self.print_parsed_response(response)
  case response
  when Hash
    response.each do |key, value|
      case key
      when 'stream'
        puts value
      else
        puts "#{key}: #{value}"
      end
    end
  when Array
    response.each do |hash|
      print_parsed_response(hash)
    end
  end
end

.remove_prefix(name) ⇒ Object



70
71
72
73
74
75
76
# File 'lib/spoon.rb', line 70

def self.remove_prefix(name)
  if name.start_with? "/"
    name[7..-1]
  else
    name[6..-1]
  end
end

.strip_slash(name) ⇒ Object



151
152
153
154
155
156
157
# File 'lib/spoon.rb', line 151

def self.strip_slash(name)
  if name.start_with? "/"
    name[1..-1]
  else
    name
  end
end