mybot 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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