mybot 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Botfile CHANGED
@@ -3,7 +3,17 @@ require "fileutils"
3
3
 
4
4
  include Messages
5
5
 
6
+ local = node "localhost", "seba",
7
+ :keys => ["/Users/seba/.ssh/id_rsa"]
8
+ local.use [
9
+ "core/fs"
10
+ ]
11
+
6
12
  namespace :mybot do
13
+ task :version do
14
+ puts Mybot::VERSION
15
+ end
16
+
7
17
  task :install do
8
18
  if File.exists? Mybot::MYBOT_PATH
9
19
  error "mybot is already installed"
@@ -1,3 +1,21 @@
1
+ ### 0.0.3
2
+ * added Utils with lib_to_path
3
+ * added require_*_installed helper
4
+ * added AWS instances support
5
+ * added nginx support with static apps
6
+ * added rails and static apps deployment
7
+ * added git.init
8
+ * added PHP support with nginx and FPM
9
+ * fixed bug when running cmd in other cmd
10
+ * refactored output formatting
11
+ * added apt.dpkg_reconfigure
12
+ * Node#run now returns Result object with STDOUT, STDERR and exit status
13
+ * added fs.mktemp
14
+ * added mysql user and dbs management routines
15
+ * added ~/.bash_profile, ~/.bashrc and ~/.profile loading
16
+ * added listeners
17
+ * added write shadows
18
+
1
19
  ### 0.0.2
2
20
  * started CHANGELOG
3
21
  * updated README to cover all available techniques
@@ -1,17 +1,23 @@
1
1
  require "mybot/core-ext/kernel"
2
+ require "mybot/core-ext/class"
3
+ require "mybot/core-ext/array"
2
4
 
3
5
  module Mybot
6
+ autoload :Aws, "mybot/aws"
4
7
  autoload :Base, "mybot/base"
5
8
  autoload :Cli, "mybot/cli"
6
9
  autoload :Command, "mybot/command"
7
10
  autoload :Commands, "mybot/commands"
8
11
  autoload :Fmt, "mybot/fmt"
9
12
  autoload :Lib, "mybot/lib"
13
+ autoload :Libs, "mybot/libs"
10
14
  autoload :Messages, "mybot/messages"
11
15
  autoload :Node, "mybot/node"
12
16
  autoload :Recipes, "mybot/recipes"
17
+ autoload :Result, "mybot/result"
13
18
  autoload :Tasks, "mybot/tasks"
14
19
  autoload :Template, "mybot/template"
20
+ autoload :Utils, "mybot/utils"
15
21
  autoload :VERSION, "mybot/version"
16
22
 
17
23
  GEM_PATH = File.dirname(File.dirname(__FILE__))
@@ -0,0 +1,54 @@
1
+ require "fog"
2
+
3
+ module Mybot
4
+ class Aws
5
+ include Messages
6
+
7
+ PROVIDER = "AWS"
8
+
9
+ def initialize(options = {})
10
+ error "access_key_id is required" unless options[:access_key_id]
11
+ error "secret_access_key is required" unless options[:secret_access_key]
12
+
13
+ @options = options
14
+ end
15
+
16
+ def aws
17
+ @aws ||= Fog::Compute.new({
18
+ :provider => PROVIDER,
19
+ :aws_access_key_id => @options[:access_key_id],
20
+ :aws_secret_access_key => @options[:secret_access_key]
21
+ })
22
+ end
23
+
24
+ def instances
25
+ aws.servers.all
26
+ end
27
+
28
+ def instance_exists?(name)
29
+ instances.each do |i|
30
+ return true if i.tags["Name"] == name and i.state == "running"
31
+ end
32
+
33
+ false
34
+ end
35
+
36
+ def instance_by_name(name)
37
+ instances.each do |i|
38
+ return i if i.tags["Name"] == name and i.state != "terminated"
39
+ end
40
+
41
+ nil
42
+ end
43
+
44
+ def instance_create(options = {})
45
+ instance = @aws.servers.create(options)
46
+
47
+ instance.wait_for do
48
+ ready?
49
+ end
50
+
51
+ instance
52
+ end
53
+ end
54
+ end
@@ -1,12 +1,12 @@
1
1
  module Mybot
2
2
  class Command
3
- attr_accessor :channel, :out, :stdout, :stderr, :exit_status
3
+ attr_accessor :channel, :out, :result
4
4
 
5
5
  def initialize(node)
6
6
  @node = node
7
- @out = @stdout = @stderr = ""
7
+ @out = ""
8
8
  @handlers = {}
9
- @exit_status = 0
9
+ @result = Result.new
10
10
  end
11
11
 
12
12
  def on(s, &block)
@@ -15,7 +15,7 @@ module Mybot
15
15
 
16
16
  def handle_stdout(data)
17
17
  @out = data
18
- @stdout += data
18
+ @result.stdout += data
19
19
  @node.fmt.stdout data
20
20
  @handlers.each do |s, proc|
21
21
  proc.call if @out.include? s
@@ -24,39 +24,35 @@ module Mybot
24
24
 
25
25
  def handle_stderr(data)
26
26
  @out = data
27
- @stderr += data
27
+ @result.stderr += data
28
28
  @node.fmt.stderr data
29
29
  @handlers.each do |s, proc|
30
30
  proc.call if @out.include? s
31
31
  end
32
32
  end
33
33
 
34
- def handle_exit
35
- filter(@stdout)
36
- end
37
-
38
34
  def handle_sudo
39
35
  on "[sudo] password" do
40
- write @node.options[:password]
36
+ write @node.options[:password], :shadow => true
41
37
  end
42
38
 
43
39
  on "Password:" do
44
- write @node.options[:password]
40
+ write @node.options[:password], :shadow => true
45
41
  end
46
42
 
47
43
  on "Sorry, try again." do
48
- @node.fmt.error "cannot handle sudo automatically, try to it manually"
44
+ @node.fmt.error "cannot handle sudo automatically, try manually"
49
45
  end
50
46
  end
51
47
 
52
- def write(data)
53
- @node.fmt.write data
54
- @channel.send_data "#{data}\n"
55
- end
48
+ def write(data, options = {})
49
+ if options[:shadow]
50
+ @node.fmt.write "***"
51
+ else
52
+ @node.fmt.write data
53
+ end
56
54
 
57
- def filter(data)
58
- data.gsub!("[sudo] password for #{@node.options[:user]}:", "")
59
- data.strip
55
+ @channel.send_data "#{data}\n"
60
56
  end
61
57
  end
62
58
  end
@@ -1,3 +1,5 @@
1
+ require "listen"
2
+
1
3
  module Mybot
2
4
  module Commands
3
5
  include Messages
@@ -6,6 +8,10 @@ module Mybot
6
8
  Node.new(host, user, options)
7
9
  end
8
10
 
11
+ def aws(options = {})
12
+ Aws.new(options)
13
+ end
14
+
9
15
  def namespace(name)
10
16
  outer_ns, @namespace = @namespace, name.to_s
11
17
  if outer_ns && outer_ns != ""
@@ -80,5 +86,23 @@ module Mybot
80
86
 
81
87
  result =~ /y|yes|Y|YES|Yes/
82
88
  end
89
+
90
+ def add_listener(*args, &block)
91
+ @listeners ||= []
92
+
93
+ l = Listen.to *args
94
+ l.change do
95
+ block.call
96
+ end
97
+
98
+ @listeners << l
99
+ info "added listener for #{args[0]}"
100
+ end
101
+
102
+ def start_listeners
103
+ info "starting listeners"
104
+ @listeners[0..-2].each { |l| l.start(false) }
105
+ @listeners.last.start(true)
106
+ end
83
107
  end
84
108
  end
@@ -0,0 +1,9 @@
1
+ class Array
2
+ def extract_options!
3
+ if last.is_a?(Hash)
4
+ pop
5
+ else
6
+ {}
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ class Class
2
+ def cattr_reader(*syms)
3
+ options = syms.extract_options!
4
+ syms.each do |sym|
5
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
6
+ unless defined? @@#{sym}
7
+ @@#{sym} = nil
8
+ end
9
+
10
+ def self.#{sym}
11
+ @@#{sym}
12
+ end
13
+ EOS
14
+
15
+ unless options[:instance_reader] == false || options[:instance_accessor] == false
16
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
17
+ def #{sym}
18
+ @@#{sym}
19
+ end
20
+ EOS
21
+ end
22
+ end
23
+ end
24
+
25
+ def cattr_writer(*syms)
26
+ options = syms.extract_options!
27
+ syms.each do |sym|
28
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
29
+ unless defined? @@#{sym}
30
+ @@#{sym} = nil
31
+ end
32
+
33
+ def self.#{sym}=(obj)
34
+ @@#{sym} = obj
35
+ end
36
+ EOS
37
+
38
+ unless options[:instance_writer] == false || options[:instance_accessor] == false
39
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
40
+ def #{sym}=(obj)
41
+ @@#{sym} = obj
42
+ end
43
+ EOS
44
+ end
45
+ self.send("#{sym}=", yield) if block_given?
46
+ end
47
+ end
48
+
49
+ def cattr_accessor(*syms, &blk)
50
+ cattr_reader(*syms)
51
+ cattr_writer(*syms, &blk)
52
+ end
53
+ end
@@ -2,65 +2,66 @@ require "colored"
2
2
 
3
3
  module Mybot
4
4
  class Fmt
5
- attr_accessor :use_color, :show_cmd,
5
+ cattr_accessor :use_color, :show_cmd, :show_cmd,
6
6
  :show_stdout, :show_stderr, :show_stdin
7
7
 
8
+ @@use_color = true
9
+ @@show_cmd = true
10
+ @@show_stdout = true
11
+ @@show_stderr = true
12
+ @@show_stdin = true
13
+
8
14
  def initialize(host, user)
9
15
  @host, @user = host, user
10
- @use_color = true
11
- @show_cmd = true
12
- @show_stdout = true
13
- @show_stderr = true
14
- @show_stdin = true
15
16
  end
16
17
 
17
18
  def run(cmd)
18
19
  run_format = "RUN"
19
- run_format = run_format.blue.bold if @use_color
20
- $stdout.print "#{prompt} #{run_format} #{cmd}\n" if @show_cmd
20
+ run_format = run_format.blue.bold if @@use_color
21
+ $stdout.print "#{prompt} #{run_format} #{cmd}\n" if @@show_cmd
21
22
  end
22
23
 
23
24
  def stdout(data)
24
- data = data.green if @use_color
25
- $stdout.print(data) if @show_stdout
25
+ data = data.green if @@use_color
26
+ $stdout.print(data) if @@show_stdout
26
27
  end
27
28
 
28
29
  def stderr(data)
29
- data = data.red if @use_color
30
- $stdout.print(data) if @show_stderr
30
+ data = data.red if @@use_color
31
+ $stdout.print(data) if @@show_stderr
31
32
  end
32
33
 
33
34
  def write(data)
34
35
  write_format = "WRITE"
35
- write_format = write_format.blue.bold if @use_color
36
+ write_format = write_format.blue.bold if @@use_color
36
37
  lf_format = "<LF>"
37
- lf_format = lf_format.red.bold if @use_color
38
- if @show_stdin
38
+ lf_format = lf_format.red.bold if @@use_color
39
+ if @@show_stdin
39
40
  $stdout.print "\n#{prompt} #{write_format} #{data}#{lf_format}\n"
40
41
  end
41
42
  end
42
43
 
43
44
  def upload(from, to)
44
45
  upload_format = "UPLOAD"
45
- upload_format = upload_format.blue.bold if @use_color
46
+ upload_format = upload_format.blue.bold if @@use_color
46
47
 
47
- if @show_cmd
48
+ if @@show_cmd
48
49
  $stdout.print "#{prompt} #{upload_format} #{from} -> #{to}\n"
49
50
  end
50
51
  end
51
52
 
52
53
  def download(from, to)
53
54
  download_format = "DOWNLOAD"
54
- download_format = download_format.blue.bold if @use_color
55
+ download_format = download_format.blue.bold if @@use_color
55
56
 
56
57
 
57
- if @show_cmd
58
+ if @@show_cmd
58
59
  $stdout.print "#{prompt} #{download_format} #{from} -> #{to}\n"
59
60
  end
60
61
  end
61
62
 
62
63
  def progress(n)
63
- if @show_cmd
64
+ if @@show_cmd
64
65
  $stdout.print "\r#{n}%"
65
66
  puts if n == 100
66
67
  end
@@ -68,7 +69,7 @@ module Mybot
68
69
 
69
70
  def error(msg)
70
71
  error_format = "ERROR"
71
- error_format = error_format.bold.red if @use_color
72
+ error_format = error_format.bold.red if @@use_color
72
73
  $stdout.print "#{prompt} #{error_format} #{msg}\n"
73
74
  abort
74
75
  end
@@ -77,7 +78,7 @@ module Mybot
77
78
 
78
79
  def prompt
79
80
  p ="[#{@user}@#{@host}]"
80
- p = p.bold if @use_color
81
+ p = p.bold if @@use_color
81
82
  end
82
83
  end
83
84
  end
@@ -1,9 +1,70 @@
1
1
  module Mybot
2
- class Lib
3
- include Messages
4
- include Commands
5
- def method_missing(name, *args, &block)
6
- error "library '#{self.class}' does not provide method #{name}"
7
- end
8
- end
2
+ class Lib
3
+ include Messages
4
+ include Commands
5
+ include Utils
6
+
7
+ def method_missing(name, options = {}, &block)
8
+ lib_path = lib_to_path(self.class.to_s)
9
+
10
+ if name =~ /require\_([a-zA-Z_]*)installed/
11
+ base_name = $1.chomp "_"
12
+
13
+ methods = []
14
+
15
+ if base_name != ""
16
+ methods = [
17
+ "#{base_name}_installed?",
18
+ "#{base_name}_install",
19
+ "#{base_name}_reconfigure"
20
+ ]
21
+ else
22
+ methods = ["installed?", "install", "reconfigure"]
23
+ end
24
+
25
+ methods[0..-2].each do |m|
26
+ unless respond_to?(m)
27
+ error "lib '#{lib_path}' does not have method '#{m}'"
28
+ end
29
+ end
30
+
31
+ unless send(methods[0], options)
32
+ send(methods[1], options)
33
+ end
34
+
35
+ if respond_to?(methods[2])
36
+ send(methods[2], options)
37
+ end
38
+
39
+ return
40
+ elsif name =~ /require\_([a-zA-Z_]*)created/
41
+ base_name = $1.chomp "_"
42
+
43
+ methods = []
44
+
45
+ if base_name != ""
46
+ methods = [
47
+ "#{base_name}_exists?",
48
+ "#{base_name}_create"
49
+ ]
50
+ else
51
+ methods = ["exists?", "create"]
52
+ end
53
+
54
+ methods.each do |m|
55
+ unless respond_to?(m)
56
+ error "lib '#{lib_path}' does not have method '#{m}'"
57
+ end
58
+ end
59
+
60
+ unless send(methods[0], options)
61
+ send(methods[1], options)
62
+ end
63
+
64
+ return
65
+ end
66
+
67
+ error "library '#{lib_path}' does not provide method #{name}"
68
+ end
69
+ end
9
70
  end