cheese 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env ruby
2
+ # cheese-setup.rb
3
+ #
4
+ # Configure cheese-tools defaults and misc information
5
+ # This is a simple run-once script which needs LOTS of refactoring and cleanup
6
+ #
7
+
8
+ require 'rubygems'
9
+ require 'highline/import'
10
+ require 'fileutils'
11
+ require 'yaml'
12
+
13
+ def draw_line(count=20)
14
+ @line = '-' * count
15
+ say "<%= color(@line, :horizontal_line) %>"
16
+ end
17
+
18
+ def draw_box
19
+ draw_line 50
20
+ yield
21
+ draw_line 50
22
+ end
23
+
24
+ CHEESE_CONF = "/etc/cheese/cheese.conf"
25
+ SUPPORTED_SCMS = {
26
+ :svn => { :name => 'Subversion', :binary => 'svnserve' } }
27
+ SUPPORTED_DBS = {
28
+ :psql => { :name => 'Postgresql', :binary => 'psql' },
29
+ :mysql => { :name => 'MySQL', :binary => 'mysql' } }
30
+ SILENCER = ">/dev/null 2>/dev/null"
31
+ begin
32
+ FileUtils.mkdir '/etc/cheese' unless File.exists? '/etc/cheese'
33
+ FileUtils.touch CHEESE_CONF
34
+
35
+ preferences = {}
36
+
37
+ # Create a color scheme, naming color patterns with symbol names.
38
+ ft = HighLine::ColorScheme.new do |cs|
39
+ cs[:headline] = [ :bold, :yellow ]
40
+ cs[:horizontal_line] = [ :bold, :white ]
41
+ cs[:important] = [ :bold, :red ]
42
+ end
43
+
44
+ # Assign that color scheme to HighLine...
45
+ HighLine.color_scheme = ft
46
+
47
+ say "<%= color('Welcome to the cheese setup utility', :headline) %>"
48
+ draw_line 37
49
+
50
+ say "Answer each of the following questions and then you'll be"
51
+ say "ready to start using cheese:"
52
+
53
+ # SCM
54
+ choose do |menu|
55
+ SUPPORTED_SCMS.each do |scm, details|
56
+ menu.choice(scm, details[:name]) do |command, extras|
57
+ preferences[:scm] = { :name => details[:name], :binary => details[:binary]}
58
+ say "What would you like the default #{details[:name]} username to be?"
59
+ preferences[:scm_user] = ask("=> ", String)
60
+ say "and what password would you like?"
61
+ preferences[:scm_pass] = ask("=> ", String){|prompt| prompt.echo = "*" }
62
+ end
63
+ end
64
+ menu.choice(:skip, "You don't want to use one") do |command, details|
65
+ preferences[:scm] = :skip
66
+ end
67
+ menu.choice(:quit, "Exit setup") { exit }
68
+ end
69
+
70
+ # Database
71
+ say "What database engine are you using?"
72
+ choose do |menu|
73
+ SUPPORTED_DBS.each do |db, details|
74
+ menu.choice(db, details[:name]) do |command, extras|
75
+ preferences[:database_type] = { :name => details[:name], :binary => details[:binary] }
76
+ end
77
+ end
78
+ menu.choice(:skip, "You don't want to use one") do |command, details|
79
+ preferences[:database_type] = :skip
80
+ end
81
+ menu.choice(:quit, "Exit setup") { exit }
82
+ end
83
+
84
+ # Rails stack combination
85
+ say "What Ruby on Rails stack are you using?"
86
+ choose do |menu|
87
+ menu.choice(:nginx, "Nginx with Mongrel") do |command, details|
88
+ preferences[:stack] = :nginx
89
+ end
90
+ menu.choice(:skip, "You don't want to use one") do |command, details|
91
+ preferences[:scm] = :skip
92
+ end
93
+ menu.choice(:quit, "Exit setup") { exit }
94
+ end
95
+
96
+ draw_box do
97
+ say "<%= color('You need a normal account for safety reasons, running as', :bold) %>"
98
+ say "<%= color('root is dangerous, so we need to do that', :bold) %>"
99
+ end
100
+
101
+ user = ask("What username would you like for logging into the system?", String)
102
+ unless user.empty?
103
+ preferences[:user] = user
104
+ %x{ useradd -c "Cheesey User" -d /home/#{preferences[:user].chomp} --create-home #{preferences[:user].chomp} #{SILENCER} }
105
+ say "and what password would you like to use with that?"
106
+ %x{ passwd #{preferences[:user]} }
107
+ %x{ addgroup scm #{SILENCER} }
108
+ %x{ usermod -g scm #{preferences[:user]} }
109
+ else
110
+ say "Skipping user creation (I assume you must have done this already then)"
111
+ end
112
+
113
+ say "Saving and setting up those selected options"
114
+
115
+ scm = %x{ which #{ preferences[:scm][:binary] } }
116
+ xinetd_service = <<-EOF
117
+ service #{ preferences[:scm][:binary] }
118
+ {
119
+ socket_type = stream
120
+ protocol = tcp
121
+ user = scm
122
+ wait = no
123
+ disable = no
124
+ server = #{ scm.chomp }
125
+ server_args = -i --root=/var/src
126
+ port = 3690
127
+ }
128
+ EOF
129
+ File.open("/etc/xinetd.d/#{preferences[:scm][:binary]}", 'w+') do |file|
130
+ file.puts xinetd_service
131
+ end
132
+ %x{ /etc/init.d/xinetd restart #{SILENCER} }
133
+
134
+ File.open(CHEESE_CONF, "w+", 0640) {|f| YAML.dump(preferences, f)}
135
+
136
+ say "Done"
137
+
138
+ rescue Errno::EPERM
139
+ puts "This script must be run with root privileges"
140
+ exit
141
+ rescue Errno::EACCES
142
+ puts "This script must be run with root privileges"
143
+ exit
144
+ end
@@ -0,0 +1,9 @@
1
+ module Cheese #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,152 @@
1
+ # controller.rb
2
+ #
3
+ # Validate the options given and delegate jobs to the other classes
4
+ #
5
+
6
+ begin
7
+ require 'rubygems'
8
+ rescue LoadError
9
+ # no rubygems to load, so we fail silently
10
+ end
11
+
12
+ require 'yaml'
13
+ require 'process'
14
+ require 'verbose'
15
+ require 'database/mysql'
16
+ require 'database/postgresql'
17
+ require 'scm/subversion'
18
+ require 'web/domain'
19
+ require 'web/mongrel'
20
+ require 'web/nginx'
21
+ require 'web/proxy'
22
+ require 'web/virtual_host'
23
+
24
+ module Cheese
25
+ class Controller
26
+
27
+ CHEESE_CONF = "/etc/cheese/cheese.conf"
28
+ NGINX_CONF = '/etc/nginx/nginx.conf'
29
+
30
+ def initialize(options={})
31
+ # Check cheese --setup has been run
32
+ unless File.exists?(CHEESE_CONF)
33
+ puts "Please run cheese --setup before using any cheese actions."
34
+ exit
35
+ end
36
+ # Need a better way of doing this, so it works in all files
37
+ Cheese::Verbose.dry_run = options.delete(:dry_run)
38
+ Cheese::Verbose.loud = options.delete(:verbose)
39
+ @preferences = YAML.load(File.open(CHEESE_CONF))
40
+ @options = options
41
+ run_actions
42
+ end
43
+
44
+ private
45
+
46
+ # Run all actions necessary
47
+ def run_actions
48
+ # List vhosts
49
+ if ( @options[:actions].include?(:web_server) || @options[:actions].include?(:list_vhosts))
50
+ @nginx = Cheese::Nginx::Config.new(NGINX_CONF)
51
+ end
52
+
53
+ if @options[:actions].include? :list_vhosts
54
+ Cheese::Verbose.log_task("listing vhosts in nginx.conf") do
55
+ begin
56
+ @nginx.domains.each_with_index {|domain, i| puts "#{i}. #{domain.vhost.domain} - #{domain.proxy.ports.size} threads" }
57
+ rescue Exception => e
58
+ puts "Error listing vhosts:"
59
+ puts e.message
60
+ puts "exiting"
61
+ exit
62
+ end
63
+ end
64
+ end
65
+
66
+ # Nginx
67
+ if @options[:actions].include? :web_server
68
+ begin
69
+ Cheese::Verbose.log_task("back up nginx.conf") do
70
+ FileUtils.cp(NGINX_CONF, NGINX_CONF + ".old") if File.exists?(NGINX_CONF)
71
+ end
72
+ rescue Errno::EPERM
73
+ puts "This script must be run with root privileges"
74
+ exit
75
+ rescue Errno::EACCES
76
+ puts "This script must be run with root privileges"
77
+ exit
78
+ end
79
+
80
+ case @options[:remove]
81
+ when false
82
+ Cheese::Verbose.log_task("create nginx vhost (#{@options[:name]})") do
83
+ @added_domain = @nginx.add @options
84
+ end
85
+ when true
86
+ Cheese::Verbose.log_task("remove nginx vhost (#{@options[:name]})") do
87
+ @removed_domain = @nginx.remove @options
88
+ end
89
+ end
90
+
91
+ @nginx.save
92
+ @nginx.restart
93
+ end
94
+
95
+ # Subversion
96
+ if @options[:actions].include? :scm
97
+ if @options[:remove]
98
+ Cheese::Verbose.log_task("remove subversion repository (#{@options[:name]})") do
99
+ svn = Cheese::Subversion::Repository.remove @options[:name]
100
+ end
101
+ else
102
+ Cheese::Verbose.log_task("add subversion repository (#{@options[:name]})") do
103
+ svn = Cheese::Subversion::Repository.create @options[:name]
104
+ end
105
+ Cheese::Verbose.log_task("set the default permissions on the repository") do
106
+ user, pass = @preferences[:scm_user].chomp, @preferences[:scm_pass].chomp
107
+ Cheese::Subversion::Repository.set_permissions( :name => @options[:name],
108
+ :access => {:anon => :none, :auth => :write},
109
+ :users => {:user => user, :pass => pass})
110
+ end
111
+ end
112
+ end
113
+
114
+ # Mongrel cluster file
115
+ if @options[:actions].include? :app_server
116
+ if @options[:remove]
117
+ Cheese::Verbose.log_task("remove the mongrel_cluster file") do
118
+ Cheese::Mongrel.remove(@removed_domain)
119
+ end
120
+ else
121
+ Cheese::Verbose.log_task("create the mongrel_cluster file") do
122
+ Cheese::Mongrel.create(@added_domain.host, @added_domain.proxy.ports)
123
+ end
124
+ end
125
+ end
126
+
127
+ # Database
128
+ if @options[:actions].include? :database
129
+ if @options[:remove]
130
+ Cheese::Verbose.log_task("drop a database") do
131
+ Cheese::Verbose.log_task(" requiring lib/#{@options[:database_type]}")
132
+ require "database/#{@options[:database_type]}"
133
+ Cheese::Verbose.log_task(" creating class #{@options[:database_type].to_s.capitalize}")
134
+ db_klass = Cheese.const_get(@options[:database_type].to_s.capitalize.intern)
135
+ Cheese::Verbose.log_task(" executing remove command on #{@options[:name]}")
136
+ db_klass.remove(@options[:name])
137
+ end
138
+ else
139
+ Cheese::Verbose.log_task("create a database") do
140
+ Cheese::Verbose.log_task(" requiring lib/#{@options[:database_type]}")
141
+ require "database/#{@options[:database_type]}"
142
+ Cheese::Verbose.log_task(" creating class #{@options[:database_type].to_s.capitalize}")
143
+ db_klass = Cheese.const_get(@options[:database_type].to_s.capitalize.intern)
144
+ Cheese::Verbose.log_task(" executing create command")
145
+ db_klass.create(@options[:name])
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ end
152
+ end
@@ -0,0 +1,50 @@
1
+ # mysql.rb
2
+ #
3
+ # Create and remove mysql databases
4
+ #
5
+
6
+ require 'highline/import'
7
+ require 'tempfile'
8
+
9
+ module Cheese
10
+
11
+ class Mysql
12
+
13
+ # create a user and new db
14
+ def self.create(name)
15
+ puts "What is the root password for MySQL?"
16
+ pass = ask("=> "){|prompt| prompt.echo = "*" }.chomp
17
+ while true
18
+ puts "What is the database password you want for #{name.gsub(".", "_")}?"
19
+ dbpass1 = ask("=> "){|prompt| prompt.echo = "*" }.chomp
20
+ puts "Confirm that"
21
+ dbpass2 = ask("=> "){|prompt| prompt.echo = "*" }.chomp
22
+ if dbpass1.chomp == dbpass2.chomp
23
+ break
24
+ else
25
+ puts "Those passwords didn't match, try again:"
26
+ end
27
+ end
28
+ puts "adding db and user"
29
+ tmpfile = Tempfile.new("mysql-create")
30
+ tmpfile.puts "CREATE DATABASE #{name.gsub(".", "_")};"
31
+ tmpfile.puts "GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON *.* TO '#{name.gsub(".", "_")}'@'localhost' IDENTIFIED BY '#{dbpass1}';"
32
+ tmpfile.close
33
+ %x{ mysql -u root -p#{pass} mysql < #{tmpfile.path} }
34
+ end
35
+
36
+ # remove a user and new db
37
+ def self.remove(name)
38
+ puts "What is the root password for MySQL?"
39
+ pass = ask("=> "){|prompt| prompt.echo = "*" }
40
+
41
+ tmpfile = Tempfile.new("mysql-drop")
42
+ tmpfile.puts "DROP DATABASE #{name.gsub(".", "_")};"
43
+ tmpfile.puts "DROP USER '#{name.gsub(".", "_")}'@'localhost';"
44
+ tmpfile.close
45
+ %x{ mysql -u root -p#{pass} < #{tmpfile.path} }
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,29 @@
1
+ # postgresql.rb
2
+ #
3
+ # Create and remove postgresql databases
4
+ #
5
+
6
+ module Cheese
7
+
8
+ class Postgresql
9
+ SILENCER = ">/dev/null 2>/dev/null"
10
+
11
+ # create a user and new db
12
+ def self.create(name)
13
+ while
14
+ puts "We need to set a database password for #{name.gsub(".", "_")}."
15
+ end
16
+
17
+ %x{ su -c "createuser -S -D -R #{name.gsub(".", "_")} -W" postgres }
18
+ %x{ su -c "createdb #{name.gsub(".", "_")}" postgres #{SILENCER} }
19
+ end
20
+
21
+ # remove a user and new db
22
+ def self.remove(name)
23
+ %x{ su -c "dropuser #{name.gsub(".", "_")}" postgres #{SILENCER} }
24
+ %x{ su -c "dropdb #{name.gsub(".", "_")}" postgres #{SILENCER} }
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,17 @@
1
+ # process.rb
2
+ #
3
+ # Run a process as a different user
4
+ # Thanks to the "Ruby Cookbook" for this one
5
+
6
+ module Process
7
+ def as_uid(uid=0)
8
+ old_euid, old_uid = Process.euid, Process.uid
9
+ Process.euid, Process.uid = uid, uid
10
+ begin
11
+ yield
12
+ ensure
13
+ Process.euid, Process.uid = old_euid, old_uid
14
+ end
15
+ end
16
+ module_function(:as_uid)
17
+ end
@@ -0,0 +1,83 @@
1
+ # subversion.rb
2
+ #
3
+ # Acts as a subversion repository
4
+ # This could be done with the svn ruby bindings, but it's simple
5
+ # stuff that for now will be fine using system
6
+
7
+ require 'fileutils'
8
+
9
+ module Cheese
10
+ module Subversion
11
+ class Repository
12
+ DEFAULT_ACCESS = { :anon => :none, :auth => :write }
13
+ SILENCER = ">/dev/null 2>/dev/null"
14
+ def self.create(name)
15
+ # Create the repo
16
+ %x{ svnadmin create /var/src/#{name} #{SILENCER} }
17
+ %x{ chown svn:svn /var/src/#{name} #{SILENCER} }
18
+ %x{ chmod -R 774 /var/src/#{name} #{SILENCER} }
19
+
20
+ folder = self.create_tmp_structure
21
+ self.import(name, folder)
22
+ end
23
+
24
+ # Create the default file structure
25
+ def self.create_tmp_structure
26
+ FileUtils.mkdir_p( File.join(Dir.tmpdir, "/svn_structure/branches")) unless File.exists? File.join(Dir.tmpdir, "/svn_structure/branches")
27
+ FileUtils.mkdir( File.join(Dir.tmpdir, "/svn_structure/trunk")) unless File.exists? File.join(Dir.tmpdir, "/svn_structure/trunk")
28
+ FileUtils.mkdir( File.join(Dir.tmpdir, "/svn_structure/tags")) unless File.exists? File.join(Dir.tmpdir, "/svn_structure/tags")
29
+ File.join(Dir.tmpdir, "/svn_structure")
30
+ end
31
+
32
+ # Set the permissions on a repository, defaults are anon-access: none and auth-access: write.
33
+ # These options can be changed with options
34
+ #
35
+ # ==== Options
36
+ # +options+
37
+ # +access+: A Hash containing :anon and :auth which can be set to either :none, :read or :write
38
+ # +users+: An Array or Hash containing user/pass combinations
39
+ # e.g. { :name => "Jamie", :password => "Chees3y" }
40
+ def self.set_permissions(options={})
41
+ access = options.delete(:access) || DEFAULT_ACCESS
42
+ name = options.delete(:name)
43
+ File.open("/var/src/#{name}/conf/svnserve.conf", "w+") do |file|
44
+ file.puts "# Generated on #{Time.now.to_s}"
45
+ file.puts "[general]"
46
+ file.puts "anon-access = #{access[:anon].to_s}"
47
+ file.puts "auth-access = #{access[:auth].to_s}"
48
+ file.puts "password-db = passwd"
49
+ end
50
+ File.open("/var/src/#{name}/conf/passwd", "w+") do |file|
51
+ file.puts "[users]"
52
+ if options[:users].is_a?Array
53
+ options[:users].each do |user, pass|
54
+ file.puts "#{user} = #{pass}"
55
+ end
56
+ elsif options[:users].is_a?Hash
57
+ file.puts "#{options[:users][:user]} = #{options[:users][:pass]}"
58
+ end
59
+ end
60
+ end
61
+
62
+ def self.remove(name)
63
+ FileUtils.rm_rf("/var/src/#{name}")
64
+ end
65
+
66
+ def self.import(name, files=[], extra_path="")
67
+ files.each do |file|
68
+ %x{ svn import #{file} file:///var/src/#{name}#{extra_path} -m "import of #{file}" }
69
+ end
70
+ end
71
+
72
+ def self.remove_file(name, files=[])
73
+ if files.is_a?Array
74
+ files.each do |file|
75
+ %x{ svn delete #{file} file:///var/src/#{name} -m "deleted #{file}" #{SILENCER} } if File.exists? file
76
+ end
77
+ else
78
+ %x{ svn delete #{files} file:///var/src/#{name} -m "deleted #{files} #{SILENCER}" } if File.exists? files
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end