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