automateit 0.70923

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data.tar.gz.sig +1 -0
  2. data/CHANGES.txt +100 -0
  3. data/Hoe.rake +35 -0
  4. data/Manifest.txt +111 -0
  5. data/README.txt +44 -0
  6. data/Rakefile +284 -0
  7. data/TESTING.txt +57 -0
  8. data/TODO.txt +26 -0
  9. data/TUTORIAL.txt +390 -0
  10. data/bin/ai +3 -0
  11. data/bin/aifield +82 -0
  12. data/bin/aitag +128 -0
  13. data/bin/automateit +117 -0
  14. data/docs/friendly_errors.txt +50 -0
  15. data/docs/previews.txt +86 -0
  16. data/env.sh +4 -0
  17. data/examples/basic/Rakefile +26 -0
  18. data/examples/basic/config/automateit_env.rb +16 -0
  19. data/examples/basic/config/fields.yml +3 -0
  20. data/examples/basic/config/tags.yml +13 -0
  21. data/examples/basic/dist/README.txt +9 -0
  22. data/examples/basic/dist/myapp_server.erb +30 -0
  23. data/examples/basic/install.log +15 -0
  24. data/examples/basic/lib/README.txt +10 -0
  25. data/examples/basic/recipes/README.txt +4 -0
  26. data/examples/basic/recipes/install.rb +53 -0
  27. data/examples/basic/recipes/uninstall.rb +6 -0
  28. data/gpl.txt +674 -0
  29. data/lib/automateit.rb +66 -0
  30. data/lib/automateit/account_manager.rb +106 -0
  31. data/lib/automateit/account_manager/linux.rb +171 -0
  32. data/lib/automateit/account_manager/passwd.rb +69 -0
  33. data/lib/automateit/account_manager/portable.rb +136 -0
  34. data/lib/automateit/address_manager.rb +165 -0
  35. data/lib/automateit/address_manager/linux.rb +80 -0
  36. data/lib/automateit/address_manager/portable.rb +37 -0
  37. data/lib/automateit/cli.rb +80 -0
  38. data/lib/automateit/common.rb +65 -0
  39. data/lib/automateit/constants.rb +33 -0
  40. data/lib/automateit/edit_manager.rb +292 -0
  41. data/lib/automateit/error.rb +10 -0
  42. data/lib/automateit/field_manager.rb +103 -0
  43. data/lib/automateit/interpreter.rb +641 -0
  44. data/lib/automateit/package_manager.rb +242 -0
  45. data/lib/automateit/package_manager/apt.rb +63 -0
  46. data/lib/automateit/package_manager/egg.rb +64 -0
  47. data/lib/automateit/package_manager/gem.rb +179 -0
  48. data/lib/automateit/package_manager/portage.rb +69 -0
  49. data/lib/automateit/package_manager/yum.rb +65 -0
  50. data/lib/automateit/platform_manager.rb +47 -0
  51. data/lib/automateit/platform_manager/darwin.rb +30 -0
  52. data/lib/automateit/platform_manager/debian.rb +26 -0
  53. data/lib/automateit/platform_manager/freebsd.rb +25 -0
  54. data/lib/automateit/platform_manager/gentoo.rb +26 -0
  55. data/lib/automateit/platform_manager/lsb.rb +40 -0
  56. data/lib/automateit/platform_manager/struct.rb +78 -0
  57. data/lib/automateit/platform_manager/uname.rb +29 -0
  58. data/lib/automateit/platform_manager/windows.rb +33 -0
  59. data/lib/automateit/plugin.rb +7 -0
  60. data/lib/automateit/plugin/base.rb +32 -0
  61. data/lib/automateit/plugin/driver.rb +218 -0
  62. data/lib/automateit/plugin/manager.rb +232 -0
  63. data/lib/automateit/project.rb +460 -0
  64. data/lib/automateit/root.rb +14 -0
  65. data/lib/automateit/service_manager.rb +79 -0
  66. data/lib/automateit/service_manager/chkconfig.rb +39 -0
  67. data/lib/automateit/service_manager/rc_update.rb +37 -0
  68. data/lib/automateit/service_manager/sysv.rb +126 -0
  69. data/lib/automateit/service_manager/update_rcd.rb +35 -0
  70. data/lib/automateit/shell_manager.rb +261 -0
  71. data/lib/automateit/shell_manager/base_link.rb +67 -0
  72. data/lib/automateit/shell_manager/link.rb +24 -0
  73. data/lib/automateit/shell_manager/portable.rb +421 -0
  74. data/lib/automateit/shell_manager/symlink.rb +32 -0
  75. data/lib/automateit/shell_manager/which.rb +25 -0
  76. data/lib/automateit/tag_manager.rb +63 -0
  77. data/lib/automateit/tag_manager/struct.rb +101 -0
  78. data/lib/automateit/tag_manager/tag_parser.rb +91 -0
  79. data/lib/automateit/tag_manager/yaml.rb +29 -0
  80. data/lib/automateit/template_manager.rb +55 -0
  81. data/lib/automateit/template_manager/base.rb +172 -0
  82. data/lib/automateit/template_manager/erb.rb +17 -0
  83. data/lib/ext/metaclass.rb +17 -0
  84. data/lib/ext/object.rb +18 -0
  85. data/lib/hashcache.rb +22 -0
  86. data/lib/helpful_erb.rb +63 -0
  87. data/lib/nested_error.rb +33 -0
  88. data/lib/queued_logger.rb +68 -0
  89. data/lib/tempster.rb +239 -0
  90. data/misc/index_gem_repository.rb +303 -0
  91. data/misc/setup_egg.rb +12 -0
  92. data/misc/setup_gem_dependencies.sh +7 -0
  93. data/misc/setup_rubygems.sh +21 -0
  94. data/misc/which.cmd +6 -0
  95. data/spec/extras/automateit_service_sysv_test +50 -0
  96. data/spec/extras/scratch.rb +15 -0
  97. data/spec/extras/simple_recipe.rb +8 -0
  98. data/spec/integration/account_manager_spec.rb +218 -0
  99. data/spec/integration/address_manager_linux_spec.rb +119 -0
  100. data/spec/integration/address_manager_portable_spec.rb +30 -0
  101. data/spec/integration/cli_spec.rb +215 -0
  102. data/spec/integration/examples_spec.rb +54 -0
  103. data/spec/integration/examples_spec_editor.rb +71 -0
  104. data/spec/integration/package_manager_spec.rb +104 -0
  105. data/spec/integration/platform_manager_spec.rb +69 -0
  106. data/spec/integration/service_manager_sysv_spec.rb +115 -0
  107. data/spec/integration/shell_manager_spec.rb +471 -0
  108. data/spec/integration/template_manager_erb_spec.rb +31 -0
  109. data/spec/spec_helper.rb +23 -0
  110. data/spec/unit/edit_manager_spec.rb +162 -0
  111. data/spec/unit/field_manager_spec.rb +79 -0
  112. data/spec/unit/hashcache_spec.rb +28 -0
  113. data/spec/unit/interpreter_spec.rb +98 -0
  114. data/spec/unit/platform_manager_spec.rb +44 -0
  115. data/spec/unit/plugins_spec.rb +253 -0
  116. data/spec/unit/tag_manager_spec.rb +189 -0
  117. data/spec/unit/template_manager_erb_spec.rb +137 -0
  118. metadata +249 -0
  119. metadata.gz.sig +0 -0
data/bin/ai ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ load File.join(File.dirname(__FILE__), "automateit")
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # XXX What can go wrong with this loading approach?
4
+ libdir = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
5
+ if File.directory?(libdir) and File.exists?(File.join(libdir, "automateit.rb"))
6
+ $LOAD_PATH.unshift(libdir)
7
+ end
8
+
9
+ require 'rubygems'
10
+ require 'optparse'
11
+ require 'automateit'
12
+
13
+ OptionParser.new do |parser|
14
+ PROG = File.basename($0)
15
+ opts = {}
16
+ parser.banner = <<EOB
17
+ #{PROG} - tool for querying AutomateIt fields
18
+
19
+ Usage: #{PROG} [options] query
20
+
21
+ Examples:
22
+ # Load 'myproject' and get value of 'user' field in 'myapp' hash:
23
+ #{PROG} -p myproject myapp#user
24
+
25
+ # Same but using environmental variable to specify project:
26
+ AUTOMATEIT_PROJECT=myproject
27
+ #{PROG} myapp#user
28
+
29
+ # Dump the 'myapp' hash contents as YAML
30
+ #{PROG} -y myapp#user
31
+
32
+ # Dump the 'myapp' hash contents as XML
33
+ #{PROG} -x myapp#user
34
+
35
+ Options:
36
+ EOB
37
+ parser.on("-p", "--project PATH", "Set project path") do |v|
38
+ opts[:project] = v
39
+ end
40
+
41
+ parser.on("-Y", "--yaml", "Dump as YAML") do |v|
42
+ opts[:yaml] = v
43
+ end
44
+
45
+ parser.on("-X", "--xml", "Dump as XML") do |v|
46
+ opts[:xml] = v
47
+ end
48
+
49
+ parser.on("-h", "--help", "Display this help message") do |v|
50
+ puts parser
51
+ exit
52
+ end
53
+
54
+ parser.on("-v", "--version", "Display version") do |v|
55
+ puts AutomateIt::VERSION
56
+ exit 0
57
+ end
58
+
59
+ args = parser.parse!.dup
60
+
61
+ # Clear ARGV so that IRB doesn't try to parse our options
62
+ opts[:args] = args
63
+ ARGV.clear
64
+
65
+ query = args.first unless args.empty?
66
+
67
+ interpreter = AutomateIt.new(:project => opts[:project])
68
+ result = interpreter.lookup(query)
69
+ if result.nil?
70
+ puts result.inspect
71
+ exit 1
72
+ elsif opts[:yaml]
73
+ puts result.to_yaml
74
+ elsif opts[:xml]
75
+ require 'active_support/core_ext/hash'
76
+ require 'active_support/core_ext/array'
77
+ puts result.to_xml
78
+ else
79
+ puts result.is_a?(String) ? result : result.inspect
80
+ end
81
+ exit 0
82
+ end
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # XXX What can go wrong with this loading approach?
4
+ libdir = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
5
+ if File.directory?(libdir) and File.exists?(File.join(libdir, "automateit.rb"))
6
+ $LOAD_PATH.unshift(libdir)
7
+ end
8
+
9
+ require 'rubygems'
10
+ require 'optparse'
11
+ require 'automateit'
12
+
13
+ OptionParser.new do |parser|
14
+ PROG = File.basename($0)
15
+ opts = {}
16
+ parser.banner = <<EOB
17
+ #{PROG} - tool for querying AutomateIt tags
18
+
19
+ Usage: #{PROG} [options] [arguments...]
20
+
21
+ Examples:
22
+ # Load 'myproject' and see if it's tagged with 'apache' or 'svn':
23
+ #{PROG} -p myproject 'apache || svn'
24
+ echo $?
25
+
26
+ # Same but using environmental variable to specify project:
27
+ AUTOMATEIT_PROJECT=myproject
28
+ #{PROG} 'apache || svn'
29
+ echo $?
30
+
31
+ # Dump the results of a query as YAML
32
+ #{PROG} -Y myapp#user
33
+
34
+ # Dump the results of a query as XML
35
+ #{PROG} -X myapp#user
36
+
37
+ Options:
38
+ EOB
39
+ parser.on("-s", "--tags", "List tags for this host") do |v|
40
+ opts[:tags] = v
41
+ end
42
+
43
+ parser.on("-f", "--tags_for HOST", "List tags for a specific host") do |v|
44
+ opts[:tags_for] = v
45
+ end
46
+
47
+ parser.on("-t", "--tagged? QUERY", "Is this host tagged with the query?") do |v|
48
+ opts[:tagged?] = v
49
+ end
50
+
51
+ parser.on("-w", "--hosts_tagged_with QUERY", "List hosts tagged with query") do |v|
52
+ opts[:hosts_tagged_with] = v
53
+ end
54
+
55
+ parser.on("-p", "--project PATH", "Set project path") do |v|
56
+ opts[:project] = v
57
+ end
58
+
59
+ parser.on("-Y", "--yaml", "Dump as YAML") do |v|
60
+ opts[:yaml] = v
61
+ end
62
+
63
+ parser.on("-X", "--xml", "Dump as XML") do |v|
64
+ opts[:xml] = v
65
+ end
66
+
67
+ parser.on("-h", "--help", "Display this help message") do |v|
68
+ puts parser
69
+ exit
70
+ end
71
+
72
+ parser.on("-v", "--version", "Display version") do |v|
73
+ puts AutomateIt::VERSION
74
+ exit 0
75
+ end
76
+
77
+ args = parser.parse!.dup
78
+
79
+ # Clear ARGV so that IRB doesn't try to parse our options
80
+ opts[:args] = args
81
+ ARGV.clear
82
+
83
+ interpreter = AutomateIt.new(:project => opts[:project])
84
+ result = nil
85
+
86
+ unless opts[:tags] or opts[:tags_for] or opts[:tagged?] or opts[:hosts_tagged_with]
87
+ if args.first
88
+ opts[:tagged?] = args.first
89
+ else
90
+ puts parser
91
+ puts "\nERROR: insufficient arguments"
92
+ exit 1
93
+ end
94
+ end
95
+
96
+ result = \
97
+ if opts[:tags]
98
+ interpreter.tags
99
+ elsif opts[:tags_for]
100
+ interpreter.tags_for(opts[:tags_for])
101
+ elsif opts[:tagged?]
102
+ exit(interpreter.tagged?(opts[:tagged?]) ? 0 : 1)
103
+ elsif opts[:hosts_tagged_with]
104
+ interpreter.hosts_tagged_with(opts[:hosts_tagged_with])
105
+ end
106
+
107
+ puts(
108
+ if result.nil?
109
+ result.inspect
110
+ elsif opts[:yaml]
111
+ result.to_yaml
112
+ elsif opts[:xml]
113
+ require 'active_support/core_ext/hash'
114
+ require 'active_support/core_ext/array'
115
+ result.to_xml
116
+ else
117
+ case result
118
+ when String: result
119
+ when Set: result.sort.to_a.join(' ')
120
+ when Array: result.sort.join(' ')
121
+ else result.inspect
122
+ end
123
+ end
124
+ )
125
+
126
+ exit 0
127
+ end
128
+
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # XXX What can go wrong with this loading approach?
4
+ libdir = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
5
+ if File.directory?(libdir) and File.exists?(File.join(libdir, "automateit.rb"))
6
+ $LOAD_PATH.unshift(libdir)
7
+ end
8
+
9
+ require 'rubygems'
10
+ require 'logger'
11
+ require 'optparse'
12
+ require 'automateit'
13
+
14
+ include AutomateIt::Constants
15
+
16
+ OptionParser.new do |parser|
17
+ PROG = File.basename($0)
18
+ opts = {}
19
+ parser.banner = <<EOB
20
+ #{PROG} - tool for automating the setup and maintenance of servers
21
+
22
+ Usage: #{PROG} [options] [recipe]
23
+
24
+ Examples:
25
+ # Start an interactive shell session
26
+ #{PROG}
27
+
28
+ # Execute a recipe
29
+ #{PROG} myrecipe.rb
30
+
31
+ # Preview the commands a recipe will run without running them
32
+ #{PROG} -n myrecipe.rb
33
+
34
+ # Eval a string
35
+ #{PROG} -e "puts tags.to_a.inspect"
36
+
37
+ Options:
38
+ EOB
39
+ parser.on("-c", "--create PATH", "Create project at path") do |v|
40
+ opts[:create] = v
41
+ end
42
+
43
+ parser.on("-p", "--project PATH", "Set project path") do |v|
44
+ opts[:project] = v
45
+ end
46
+
47
+ parser.on("-n", "--preview", "Preview without executing commands") do |v|
48
+ opts[:preview] = v
49
+ end
50
+
51
+ parser.on("-e", "--eval STRING", "Evaluate string") do |v|
52
+ opts[:eval] = v
53
+ end
54
+
55
+ parser.on("-q", "--quiet", "Print only errors") do |v|
56
+ opts[:verbosity] = Logger::ERROR
57
+ end
58
+
59
+ parser.on("-d", "--debug", "Print debugging information") do |v|
60
+ opts[:verbosity] = Logger::DEBUG
61
+ end
62
+
63
+ parser.on("-T", "--trace", "Display raw exception traces") do |v|
64
+ opts[:friendly_exceptions] = ! v
65
+ end
66
+
67
+ parser.on("-h", "--help", "Display this help message") do |v|
68
+ puts parser
69
+ exit
70
+ end
71
+
72
+ parser.on("-v", "--version", "Display version") do |v|
73
+ puts AutomateIt::VERSION
74
+ exit 0
75
+ end
76
+
77
+ args = parser.parse!.dup
78
+
79
+ # Clear ARGV so that IRB doesn't try to parse our options
80
+ opts[:args] = args
81
+ ARGV.clear
82
+
83
+ opts[:recipe] = args.first unless args.empty?
84
+
85
+ # Save vars because +run+ will delete opts
86
+ argscopy = args.clone
87
+ optscopy = opts.clone
88
+
89
+ begin
90
+ rv = AutomateIt::CLI.run(opts)
91
+ rescue Exception => e
92
+ msg = nil
93
+ if opts[:friendly_exceptions] != false and e.is_a?(AutomateIt::Error)
94
+ # Friendly message
95
+ msg = PERROR+e.message
96
+ msg << "\n\n"+PNOTE+"Use 'automateit --trace' to see complete backtrace"
97
+ else
98
+ # Raw backtrace
99
+ puts PERROR+"AutomateIt error trace:"
100
+ stack = e.backtrace.clone
101
+ msg = "#{stack.shift}: #{e.message} (#{e.exception.class})}";
102
+ for line in stack
103
+ msg << "\n "+line
104
+ end
105
+ end
106
+ puts msg
107
+ exit 1
108
+ rescue SysExit => e
109
+ # Don't display errors when exit gets called
110
+ end
111
+ if optscopy[:create] or optscopy[:eval] or argscopy.size > 0
112
+ exit rv ? 0 :1
113
+ else
114
+ # CTRL-D ends the line prematurely, so add a newline
115
+ puts
116
+ end
117
+ end
@@ -0,0 +1,50 @@
1
+ == User-friendly error messages
2
+
3
+ AutomateIt provides user-friendly error messages that make it easier to fix
4
+ problems in recipes and templates. These pinpoint the cause and show code
5
+ snippets.
6
+
7
+ For example, one of the sample recipes is executed -- but there's a problem and
8
+ the output is shown below.
9
+
10
+ The message is telling us the error happened in the
11
+ 'examples/basic/recipes/install.rb' recipe at line 47. The first snippet shows
12
+ the end of a failed TemplateManager +render+ call.
13
+
14
+ In the second code snippet, we see there was a problem with the ERB template
15
+ 'dist/myapp_server.erb'. This template failed at line 5 because it couldn't
16
+ find a variable called +pat+.
17
+
18
+ With the help of the second snippet, we quickly see that there's a typo -- that
19
+ bad variable should have been +path+. Problem solved!
20
+
21
+ root@kagami> automateit -n examples/basic/recipes/install.rb
22
+ !! Problem with recipe 'examples/basic/recipes/install.rb' at line 47
23
+
24
+ 41 :to => "/etc/init.d/myapp_server",
25
+ 42 :mode => 0555,
26
+ 43 :locals => {
27
+ 44 :path => lookup(:path),
28
+ 45 :user => lookup(:user),
29
+ 46 :port => lookup(:port),
30
+ * 47 }
31
+ 48 )
32
+ 49
33
+
34
+ (NestedError) Problem with template 'dist/myapp_server.erb' at line 5:
35
+
36
+ 1 #!/usr/bin/env ruby
37
+ 2
38
+ 3 user = "<%=user%>"
39
+ 4 port = "<%=port%>"
40
+ * 5 path = "<%=pat%>"
41
+ 6 pid = "mongrel.pid"
42
+ 7
43
+
44
+ (NameError) undefined local variable or method `pat' for #<AutomateIt::TemplateManager::ERB:0xb78a4e8c>
45
+ /home/igal/workspace/automateit/app/lib/helpful_erb.rb:60:in `result'
46
+ /home/igal/workspace/automateit/app/lib/automateit/template_manager/erb.rb:105:in `render'
47
+ (eval):2:in `render'
48
+ examples/basic/recipes/install.rb:47:in `invoke'
49
+
50
+ => Use 'automateit --trace' to see complete backtrace
@@ -0,0 +1,86 @@
1
+ == Previews
2
+
3
+ AutomateIt provides a way to preview commands without actually running them.
4
+ Read the TUTORIAL.txt[link:files/TUTORIAL_txt.html] to learn the basic previewing concepts and commands.
5
+
6
+ === WARNING: Previewing code can be dangerous!
7
+
8
+ AutomateIt only provides logic for previewing its own commands. Recipe authors
9
+ are responsible for providing previewing logic for their own custom code.
10
+
11
+ Here's what *not* to do with previews:
12
+
13
+ puts "Hello!"
14
+
15
+ The above +puts+ method will execute in both preview and non-preview modes.
16
+ To execute custom code only in a specific mode, wrap it with conditionals.
17
+
18
+ For example:
19
+
20
+ if preview?
21
+ puts "This is a preview"
22
+ end
23
+
24
+ preview_for("PREVIEW: Will run custom commands") do
25
+ puts "Custom commands"
26
+ end
27
+
28
+ When in preview mode, the above recipe will display:
29
+
30
+ This is a preview
31
+ => PREVIEW: Will run custom commands
32
+
33
+ When run normally without preview mode:
34
+
35
+ Custom commands
36
+
37
+ Therefore, wrap all non-AutomateIt commands (e.g. +system+) that shouldn't be
38
+ executed during the preview with conditionals.
39
+
40
+ === WARNING: Changing directories during preview can be dangerous!
41
+
42
+ AutomateIt will only *pretend* to make directories in preview mode. In
43
+ preview mode, it will also only *pretend* to change into non-existent
44
+ directories when using commands like #cd, #mkdir and #mktempdircd.
45
+
46
+ This can be *disastrous* if you're executing non-AutomateIt commands (e.g.
47
+ +system+) that use *relative* *paths* and expect to be run inside the
48
+ newly-created temporary directory because the +chdir+ didn't actually happen.
49
+
50
+ For example:
51
+
52
+ # DON'T EVER DO THIS!!!
53
+ mkdir_p "/tmp/foo/bar" do
54
+ system "echo 'I'm going to do: rm -rf *'"
55
+ end
56
+
57
+ If that directory didn't already exist, then running the above code in
58
+ preview mode would cause the +system+ command to actually run! If that wasn't
59
+ an +echo+ command, it would have deleted the contents of your *current*
60
+ directory -- not the <tt>/tmp/foo/bar</tt> directory -- because that
61
+ directory wasn't actually created due to the preview mode!
62
+
63
+ The correct way to write the above example is:
64
+
65
+ mkdir_p "/tmp/foo/bar" do
66
+ preview_for("PREVIEW: Deleting all files in directory /tmp/foo/bar") do
67
+ system "echo 'I'm going to do: rm -rf *'"
68
+ end
69
+ end
70
+
71
+ The Interpreter#preview_for method provides conditional execution of blocks.
72
+ When running in preview mode, it will display the supplied message and not
73
+ execute the block containing the +system+ command:
74
+
75
+ => PREVIEW: Deleting all files in directory /tmp/foo/bar
76
+
77
+ When running without preview mode, the method will not display the message
78
+ but will call block, generating the following output:
79
+
80
+ ** echo 'I'm going to do: rm -rf *'"
81
+ I'm going to do: rm -rf *
82
+
83
+ === Conclusion
84
+
85
+ Keeping the preview issues in mind and wrapping custom code with conditionals
86
+ will help you write code that can be safely previewed.