cheese 0.0.1

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.
@@ -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