lib/jarl/application.rb in jarl-0.7.0 vs lib/jarl/application.rb in jarl-0.8.1
- old
+ new
@@ -1,9 +1,9 @@
module Jarl
class Application
attr_reader :group, :name, :hostname, :base_path
- attr_reader :image, :volumes, :ports, :environment, :entrypoint, :command
+ attr_reader :image, :scale, :volumes, :ports, :environment, :entrypoint, :command
attr_reader :serial
# Create Application object from application definition:
#
# app_name:
@@ -20,10 +20,14 @@
@base_path = base_path
@image = params['image'] || fail("Application '#{self}' has no 'image' defined")
unless @image.is_a?(String)
fail "Application '#{self}' has invalid 'image' definition, String is expected"
end
+ @scale = params['scale'] || 1
+ unless @scale.is_a?(Integer) && @scale > 0
+ fail "Application '#{self}' has invalid 'scale' definition, Integer > 0 is expected"
+ end
@volumes = params['volumes'] || []
unless @volumes.is_a?(Array)
fail "Application '#{self}' has invalid 'volumes' definition, Array is expected"
end
@ports = params['ports'] || []
@@ -57,22 +61,46 @@
def image_is_a_registry_path?
image =~ /^.+:\d+\//
end
def running?
- instances.size > 0
+ instances.any?(&:running?)
end
def instances
- Docker.containers_running.select { |c| c.name =~ /^#{full_name}(\.\d+)?$/ }.map do |c|
- Instance.new(self, c)
+ running_instances + stopped_instances
+ end
+
+ def running_containers
+ @running_containers ||= Docker.containers_running.select do |c|
+ c.name =~ /^#{full_name}(\.\d+)?$/
end
end
- # Start +scale+ instances of the application
+ def running_instances
+ @running_instances ||= running_containers.map do |c|
+ n = c.name.sub(/^#{full_name}\.?/, '')
+ n = n.empty? ? nil : n.to_i
+ Instance.new(self, n, c)
+ end
+ end
+
+ def stopped_instances
+ return @stopped_instances if @stopped_instances
+ n_range = scale == 1 ? [nil] : (1..scale).to_a
+ @stopped_instances = n_range.reject do |n|
+ running_instances.map(&:n).include?(n)
+ end
+ @stopped_instances = @stopped_instances.map do |n|
+ Instance.new(self, n, nil)
+ end
+ @stopped_instances
+ end
+
+ # Start instances of the application
#
- def start(scale = 1)
+ def start
instances.map(&:stop!) if running?
if scale > 1
scale.times { |n| Instance.start(self, n + 1) }
else
Instance.start(self)
@@ -127,60 +155,74 @@
end
# Application::Instance represents a single running instance of the application
#
class Instance
- attr_reader :application, :container
- def initialize(application, container)
+ attr_reader :application, :n, :container
+
+ # @param application [Application]
+ # @param n [nil,Integer] Instance number, nil if an instance is the primary instance
+ # @param container [nil,Docker::Container] Running container, if present
+ #
+ def initialize(application, n, container)
@application = application
+ @n = n
@container = container
end
+ def running?
+ !@container.nil?
+ end
+
+ def full_name
+ n ? "#{application.full_name}.#{n}" : application.full_name
+ end
+
+ def hostname
+ n ? "#{application.hostname}-#{n}" : application.hostname
+ end
+
def stop!
+ return unless running?
@container.stop!
end
- def name
- @container.name
- end
+ def start!
+ return if running?
+ # puts esc_yellow("Starting #{application.name}.#{n}") if n
- def n
- suffix = @container.name.split('.').last
- suffix =~ /^\d+$/ ? suffix : nil
+ Docker.start(
+ name: full_name,
+ hostname: hostname,
+ image: application.image_name,
+ volumes: application.volumes,
+ ports: application.ports,
+ environment: application.environment,
+ command: application.command
+ )
end
def tail_log(*_args)
+ return unless running?
color_code = Console::Colors::SEQUENCE[application.serial % Console::Colors::SEQUENCE.size]
begin
- instance_no = n ? ".#{n}" : ''
IO.popen "docker logs -f #{container.id}", 'r' do |p|
str = '<<< STARTED >>>'
while str
str = p.gets
str.split("\n").each do |s|
- puts "#{esc_color color_code, application.full_name}#{instance_no}: #{s}"
+ puts "#{esc_color color_code, full_name}: #{s}"
end
end
end
rescue Interrupt
#
end
end
def ssh(command = nil)
+ fail "Failed to open SSH, no running container for '#{full_name}'" unless running?
container.open_ssh_session!(Jarl.config.params, command)
- end
-
- def self.start(application, n = nil)
- Docker.start(
- name: (n ? "#{application.full_name}.#{n}" : application.full_name),
- hostname: (n ? "#{application.hostname}-#{n}" : application.hostname),
- image: application.image_name,
- volumes: application.volumes,
- ports: application.ports,
- environment: application.environment,
- command: application.command
- )
end
end # class Instance
end # class Application
end # module Jarl