jarl 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d5f658f6a2817ddf675c13d89d831c744dd27fcf
4
- data.tar.gz: 087abc1978c7461efc0e2b2154b321ad4c0c1285
3
+ metadata.gz: 970993e9185345d4b00ebacc7f220e3859530366
4
+ data.tar.gz: 65c05fe392e5b9b61860141927b71da5556258db
5
5
  SHA512:
6
- metadata.gz: abfa4bd3f766e2d50352076b32ab0d1e56151fddd19ea8c3c769e44d971e11eecc0148c6187c6077a0fff02b77befaa1e7567507467a1f40cf1a2ed2e2513735
7
- data.tar.gz: 1f397a352b7a36204e4ad6888235b7bf0b34d0d267b1084fbbd0d4bb6fc562bc22dd0078e92365d6308f9c2832216c655bd9431317694315317b06be772d5256
6
+ metadata.gz: 97aa717a7ae7d644ec8fce6a063c8bbf54b7cb4c2db911304236baa57e43162d3f839a903951cdfca4024bb84c9ad5f09cd66553d3dbe7cbabe9402c3767e4ad
7
+ data.tar.gz: 67c50f92173a2ca9e6a7c5187aaa0354fb9a4fad674937eaeed1e69d11b3f6ca4cd2b128e2175af1b1d5679755a6b01365d405187b8a4857e614409f03c334f1
data/bin/jarl CHANGED
@@ -2,4 +2,9 @@
2
2
 
3
3
  require_relative '../lib/jarl'
4
4
 
5
- Jarl::CLI.start
5
+ begin
6
+ Jarl::CLI.start
7
+ rescue StandardError => e
8
+ puts esc_red "FATAL: #{e}"
9
+ puts e.backtrace.join("\n") if ARGV.include?('--debug')
10
+ end
@@ -1,6 +1,7 @@
1
1
  module Jarl
2
2
  class Application
3
- attr_reader :group, :name, :image, :volumes, :ports, :environment, :entrypoint, :command
3
+ attr_reader :group, :name, :hostname
4
+ attr_reader :image, :volumes, :ports, :environment, :entrypoint, :command
4
5
 
5
6
  # Create Application object from application definition:
6
7
  #
@@ -39,6 +40,8 @@ module Jarl
39
40
  if @command && !@command.is_a?(String)
40
41
  fail "Application '#{self}' has invalid 'command' definition, String is expected"
41
42
  end
43
+ @serial = self.class.next_serial
44
+ @hostname = @name
42
45
  end
43
46
 
44
47
  def full_name
@@ -61,6 +64,7 @@ module Jarl
61
64
  running_container.stop! if running?
62
65
  Docker.start(
63
66
  name: full_name,
67
+ hostname: hostname,
64
68
  image: image_name,
65
69
  volumes: volumes,
66
70
  ports: ports,
@@ -69,6 +73,23 @@ module Jarl
69
73
  )
70
74
  end
71
75
 
76
+ def execute(execute_command, args)
77
+ Docker.execute(
78
+ name: full_name,
79
+ hostname: hostname,
80
+ image: image_name,
81
+ volumes: volumes,
82
+ ports: ports,
83
+ environment: environment,
84
+ command: (execute_command || command || '') + ' ' + args.join(' ')
85
+ )
86
+ end
87
+
88
+ def ssh
89
+ fail 'Not a running application' unless running?
90
+ running_container.open_ssh_session!(Jarl.config.params)
91
+ end
92
+
72
93
  def build
73
94
  fail 'Not a file based image' unless image_is_a_path?
74
95
  Docker::Image.new(image_name, image_path).build!
@@ -83,11 +104,17 @@ module Jarl
83
104
  end
84
105
 
85
106
  def show_log(*_args)
107
+ color_code = Console::Colors::SEQUENCE[@serial % Console::Colors::SEQUENCE.size]
86
108
  return unless running?
87
109
  begin
88
110
  IO.popen "docker logs -f #{running_container.id}", 'r' do |p|
89
111
  str = '<<< STARTED >>>'
90
- puts "#{esc_yellow full_name}: #{str}" while str = p.gets
112
+ while str
113
+ str = p.gets
114
+ str.split("\n").each do |s|
115
+ puts "#{esc_color color_code, full_name}: #{s}"
116
+ end
117
+ end
91
118
  end
92
119
  rescue Interrupt
93
120
  #
@@ -97,5 +124,11 @@ module Jarl
97
124
  def to_s
98
125
  full_name
99
126
  end
127
+
128
+ def self.next_serial
129
+ @current_serial ||= 0
130
+ @current_serial += 1
131
+ @current_serial - 1
132
+ end
100
133
  end # class Application
101
134
  end # module Jarl
data/lib/jarl/base.rb CHANGED
@@ -1,8 +1,12 @@
1
1
  module Jarl
2
+ DEFAULT_JARL_CONFIG_PATH = '~/.jarl'
3
+
2
4
  #
3
5
  # Load config and application definitions
4
6
  #
5
- def self.load
7
+ def self.load(options)
8
+ load_config(options['config'] || DEFAULT_JARL_CONFIG_PATH)
9
+ # puts "Jarl::CLI.options: #{options}"
6
10
  abort 'Docker is not installed' unless Docker.installed?
7
11
  if Jarl.jarl_files.empty?
8
12
  abort 'No *.jarl files found'
@@ -12,6 +16,13 @@ module Jarl
12
16
  true
13
17
  end
14
18
 
19
+ #
20
+ # Returns current config
21
+ #
22
+ def self.config
23
+ @config
24
+ end
25
+
15
26
  #
16
27
  # Returns list of found *.jarl files
17
28
  #
@@ -24,7 +35,7 @@ module Jarl
24
35
  def self.applications
25
36
  @applications ||= jarl_files.map do |jf|
26
37
  begin
27
- jf.applications.map { |app_name, params| Application.new(jf.name, app_name, params) }
38
+ jf.applications
28
39
  rescue StandardError => e
29
40
  abort "Failed to parse application definition in file '#{jf.path}': #{e}"
30
41
  end
@@ -39,6 +50,12 @@ module Jarl
39
50
 
40
51
  private
41
52
 
53
+ def self.load_config(filename)
54
+ @config = Config.new(filename)
55
+ rescue StandardError => e
56
+ raise "Failed to load config file '#{filename}': #{e}"
57
+ end
58
+
42
59
  def self.load_jarl_files
43
60
  Pathname.glob(Pathname.pwd + '**' + '*.jarl').map do |p|
44
61
  JarlFile.new(p)
data/lib/jarl/cli.rb CHANGED
@@ -8,20 +8,39 @@ module Jarl
8
8
  aliases: '-c',
9
9
  type: :string,
10
10
  desc: 'Use specified config file (defaul: ~/.jarl)'
11
+ class_option :debug
11
12
 
12
13
  #
13
- desc 'status [NAME]', 'Show applications statuses'
14
+ desc 'config', 'Show current configuration'
15
+ def config
16
+ Jarl.load(options)
17
+ puts esc_yellow('config:') + " #{Jarl.config.path}"
18
+ Jarl.config.params.each do |key, value|
19
+ puts " #{key}: #{value.inspect}"
20
+ end
21
+ puts esc_yellow('jarl files:')
22
+ Jarl.jarl_files.each do |jarl_file|
23
+ puts " #{jarl_file.path}"
24
+ jarl_file.applications.each do |app|
25
+ puts " #{app.name}"
26
+ end
27
+ end
28
+ # show_jarl_applications_status(apps)
29
+ end
30
+
31
+ #
32
+ desc 'status [NAME]', '(default) Show applications statuses'
14
33
  def status(name = nil)
15
- Jarl.load
34
+ Jarl.load(options)
16
35
  apps = name ? Jarl.find_applications_by(name) : Jarl.applications
17
36
  show_jarl_applications_status(apps)
18
37
  end
19
38
  default_task :status
20
39
 
21
40
  #
22
- desc 'up [NAME]', '(Re)start applications'
41
+ desc 'up [NAME]', 'Start or restart applications'
23
42
  def up(name = nil)
24
- Jarl.load
43
+ Jarl.load(options)
25
44
  apps = name ? Jarl.find_applications_by(name) : Jarl.applications
26
45
  apps.each do |app|
27
46
  puts esc_green(app.running? ? "Restarting '#{app}'..." : "Starting '#{app}'...")
@@ -33,7 +52,7 @@ module Jarl
33
52
  #
34
53
  desc 'down [NAME]', 'Stop applications'
35
54
  def down(name = nil)
36
- Jarl.load
55
+ Jarl.load(options)
37
56
  apps = name ? Jarl.find_applications_by(name) : Jarl.applications
38
57
  apps.each do |app|
39
58
  next unless app.running?
@@ -42,11 +61,29 @@ module Jarl
42
61
  end
43
62
  end
44
63
 
64
+ desc 'execute NAME [COMMAND ...]', 'Run a single command against application image'
65
+ def execute(name, command = nil, *args)
66
+ Jarl.load(options)
67
+ app = Jarl.find_applications_by(name).first
68
+ abort "Failed to find application by name: '#{name}'" unless app
69
+ app.execute(command, args)
70
+ end
71
+
72
+ #
73
+ desc 'ssh NAME', 'Open SSH session to a running application'
74
+ def ssh(name)
75
+ Jarl.load(options)
76
+ app = Jarl.find_applications_by(name).first
77
+ abort "Failed to find application by name: '#{name}'" unless app
78
+ abort "Application is not running: '#{app.full_name}'" unless app.running?
79
+ app.ssh
80
+ end
81
+
45
82
  #
46
83
  option :ip, type: :boolean, desc: 'Show only IPs'
47
84
  desc 'inspect [NAME]', 'Inspect applications'
48
85
  def inspect(name = nil)
49
- Jarl.load
86
+ Jarl.load(options)
50
87
  apps = name ? Jarl.find_applications_by(name) : Jarl.applications
51
88
  apps.each do |app|
52
89
  if options[:ip]
@@ -57,9 +94,9 @@ module Jarl
57
94
  end
58
95
  end
59
96
 
60
- desc 'build [NAME]', '(Re)build docker images'
97
+ desc 'build [NAME]', 'Rebuild docker images for Dockerfile based applications'
61
98
  def build(name = nil)
62
- Jarl.load
99
+ Jarl.load(options)
63
100
  apps = name ? Jarl.find_applications_by(name) : Jarl.applications
64
101
  apps.select(&:image_is_a_path?).each do |app|
65
102
  puts esc_yellow "Building image for '#{app}'..."
@@ -69,7 +106,7 @@ module Jarl
69
106
 
70
107
  desc 'logs [NAME]', 'Show log output for applications'
71
108
  def logs(name = nil)
72
- Jarl.load
109
+ Jarl.load(options)
73
110
  apps = name ? Jarl.find_applications_by(name) : Jarl.applications
74
111
  threads = []
75
112
  apps.select(&:running?).each do |app|
@@ -106,7 +143,6 @@ module Jarl
106
143
  ['UPTIME', 12],
107
144
  ['IP', 12],
108
145
  ['PORTS']
109
- # ['IMAGE']
110
146
  )
111
147
  apps.each do |app|
112
148
  container = app.running_container
@@ -116,17 +152,8 @@ module Jarl
116
152
  (app.running? ? [seconds_to_human(container.uptime), 12, :yellow] : ['', 12]),
117
153
  (app.running? ? [container.ip, 12, :yellow] : ['', 12]),
118
154
  (app.running? ? [container.ports.map { |p| "#{p[:from]}"}.join(', ')] : [''])
119
-
120
- # (app.image_is_a_path? ? ["path: #{app.image}"] : [app.image])
121
155
  )
122
156
  end
123
- # puts "#{app.full_name} (#{app.image})"
124
- # puts " image: #{app.image}"
125
- # puts " volumes: #{app.volumes}"
126
- # puts " ports: #{app.ports}"
127
- # puts " environment: #{app.environment}"
128
- # puts " entrypoint: #{app.entrypoint}"
129
- # puts " command: #{app.command}"
130
157
  end
131
158
 
132
159
  def show_jarl_application_inspect(app)
@@ -143,8 +170,6 @@ module Jarl
143
170
  puts " IP: #{esc_yellow container.ip}"
144
171
  puts " ports: #{esc_yellow container.ports.map { |p| "#{p[:from]}->#{p[:to]}"}.join(', ')}"
145
172
  puts " volumes: #{esc_yellow container.params['Volumes']}"
146
- # puts " ps: #{esc_yellow container.ps}"
147
- # puts " params: #{esc_yellow container.params}"
148
173
  end
149
174
  end # class CLI
150
175
  end # module Jarl
@@ -0,0 +1,23 @@
1
+ require 'yaml'
2
+ require 'pathname'
3
+
4
+ module Jarl
5
+ class Config
6
+ attr_reader :path, :params
7
+
8
+ def initialize(path)
9
+ @path = Pathname.new(path).expand_path
10
+ load
11
+ end
12
+
13
+ def [](key)
14
+ @params[key]
15
+ end
16
+
17
+ private
18
+
19
+ def load
20
+ @params = YAML.load File.read(path)
21
+ end
22
+ end # class Config
23
+ end # module Jarl
data/lib/jarl/console.rb CHANGED
@@ -25,34 +25,41 @@ module Console
25
25
  end # module Utils
26
26
 
27
27
  module Colors
28
+ SEQUENCE = %w(31 32 33 34 35 36 37 31;1 32;1 33;1 34;1 35;1 36;1 37;1)
28
29
  # Returns ANSI escaped string.
29
30
  #
30
31
  def esc_string(esc, text)
31
32
  esc + text.to_s + "\e[0m"
32
33
  end
33
34
 
35
+ # Returns ANSI escaped string for the colored text.
36
+ #
37
+ def esc_color(color_code, text)
38
+ esc_string "\e[#{color_code}m", text
39
+ end
40
+
34
41
  # Returns ANSI escaped string for the red colored text.
35
42
  #
36
43
  def esc_red(text)
37
- esc_string "\e[31m", text
44
+ esc_color 31, text
38
45
  end
39
46
 
40
47
  # Returns ANSI escaped string for the green colored text.
41
48
  #
42
49
  def esc_green(text)
43
- esc_string "\e[32m", text
50
+ esc_color 32, text
44
51
  end
45
52
 
46
53
  # Returns ANSI escaped string for the yellow colored text.
47
54
  #
48
55
  def esc_yellow(text)
49
- esc_string "\e[33m", text
56
+ esc_color 33, text
50
57
  end
51
58
 
52
59
  # Returns ANSI escaped string for the blue colored text.
53
60
  #
54
61
  def esc_blue(text)
55
- esc_string "\e[34m", text
62
+ esc_color 34, text
56
63
  end
57
64
 
58
65
  # Returns ANSI escaped string for the bold text.
data/lib/jarl/docker.rb CHANGED
@@ -93,6 +93,8 @@ module Docker
93
93
  # Start container defined by params
94
94
  #
95
95
  def self.start(params)
96
+ container_name = params[:name]
97
+ Docker::Container.clean_containers(container_name)
96
98
  opts = []
97
99
  opts << params[:volumes].map do |v|
98
100
  "-v #{v}"
@@ -104,8 +106,30 @@ module Docker
104
106
  "-e #{k}=#{v}"
105
107
  end.join(' ')
106
108
  docker_cmd = "docker run -d #{opts.join(' ')} " \
107
- " --hostname #{params[:name]} " \
108
- " --name #{params[:name]} #{params[:image]} #{params[:command]}"
109
+ " --hostname #{params[:hostname]} " \
110
+ " --name #{container_name} #{params[:image]} #{params[:command]}"
111
+ # puts docker_cmd
112
+ sh docker_cmd
113
+ end
114
+
115
+ # Execute container in foreground, defined by params
116
+ #
117
+ def self.execute(params)
118
+ container_name = "#{params[:name]}.execute"
119
+ Docker::Container.clean_containers(container_name)
120
+ opts = []
121
+ opts << params[:volumes].map do |v|
122
+ "-v #{v}"
123
+ end.join(' ')
124
+ opts << params[:ports].map do |p|
125
+ "-p #{p}"
126
+ end.join(' ')
127
+ opts << params[:environment].map do |k, v|
128
+ "-e #{k}=#{v}"
129
+ end.join(' ')
130
+ docker_cmd = "docker run -t -i --rm #{opts.join(' ')} " \
131
+ " --hostname #{params[:hostname]} " \
132
+ " --name #{container_name} #{params[:image]} #{params[:command]}"
109
133
  # puts docker_cmd
110
134
  sh docker_cmd
111
135
  end
@@ -195,9 +219,16 @@ module Docker
195
219
  end
196
220
  end
197
221
 
198
- def open_ssh_session!
199
- ssh_flags = "-oStrictHostKeyChecking=no -i #{INSECURE_KEY_PATH}"
200
- sh "ssh #{ssh_flags} root@#{ip}"
222
+ def open_ssh_session!(params = {})
223
+ ssh_flags = ['-oStrictHostKeyChecking=no']
224
+ if params['ssh_identity']
225
+ ssh_flags << "-i #{params['ssh_identity']}" if params['ssh_identity'].is_a?(String)
226
+ if params['ssh_identity'].is_a?(Array)
227
+ ssh_flags << params['ssh_identity'].map { |i| "-i #{i}" }
228
+ end
229
+ end
230
+ ssh_user = params['ssh_user'] ? "#{params['ssh_user']}@" : ''
231
+ sh "ssh #{ssh_flags.join(' ')} #{ssh_user}#{ip}"
201
232
  end
202
233
 
203
234
  def stop!
@@ -3,18 +3,23 @@ require 'pathname'
3
3
 
4
4
  module Jarl
5
5
  class JarlFile
6
- attr_reader :path, :name, :applications
6
+ attr_reader :path, :name
7
7
 
8
8
  def initialize(path)
9
- @path = Pathname.new(path)
9
+ @path = Pathname.new(path).expand_path
10
10
  @name = @path.basename('.jarl')
11
- load
11
+ end
12
+
13
+ def applications
14
+ @applications ||= load_applications
12
15
  end
13
16
 
14
17
  private
15
18
 
16
- def load
17
- @applications = YAML.load File.read(path)
19
+ def load_applications
20
+ YAML.load(File.read(path)).map do |app_name, params|
21
+ Application.new(name, app_name, params)
22
+ end
18
23
  end
19
24
 
20
25
  end # class JarlFile
data/lib/jarl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Jarl
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
data/lib/jarl.rb CHANGED
@@ -5,6 +5,7 @@
5
5
  require 'jarl/base'
6
6
  require 'jarl/version'
7
7
  require 'jarl/cli'
8
+ require 'jarl/config'
8
9
  require 'jarl/application'
9
10
  require 'jarl/jarl_file'
10
11
  require 'jarl/docker'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jarl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Kukushkin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-03 00:00:00.000000000 Z
11
+ date: 2015-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -85,6 +85,7 @@ files:
85
85
  - lib/jarl/application.rb
86
86
  - lib/jarl/base.rb
87
87
  - lib/jarl/cli.rb
88
+ - lib/jarl/config.rb
88
89
  - lib/jarl/console.rb
89
90
  - lib/jarl/docker.rb
90
91
  - lib/jarl/jarl_file.rb