machines 0.5.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.
- data/.gitignore +11 -0
- data/EXAMPLES.md +18 -0
- data/Gemfile +4 -0
- data/Guardfile +14 -0
- data/INSTALL.md +25 -0
- data/LICENSE +23 -0
- data/README.md +271 -0
- data/Rakefile +60 -0
- data/TODO.md +92 -0
- data/bin/machines +6 -0
- data/lib/machines/app_settings.rb +54 -0
- data/lib/machines/base.rb +13 -0
- data/lib/machines/checks.rb +63 -0
- data/lib/machines/cloud_machine.rb +33 -0
- data/lib/machines/command.rb +86 -0
- data/lib/machines/commandline.rb +148 -0
- data/lib/machines/configuration.rb +49 -0
- data/lib/machines/core.rb +117 -0
- data/lib/machines/database.rb +17 -0
- data/lib/machines/file_operations.rb +104 -0
- data/lib/machines/help.rb +30 -0
- data/lib/machines/installation.rb +151 -0
- data/lib/machines/log_command.rb +22 -0
- data/lib/machines/logger.rb +65 -0
- data/lib/machines/machinesfile.rb +25 -0
- data/lib/machines/named_buffer.rb +9 -0
- data/lib/machines/questions.rb +15 -0
- data/lib/machines/services.rb +24 -0
- data/lib/machines/upload.rb +29 -0
- data/lib/machines/version.rb +4 -0
- data/lib/machines.rb +19 -0
- data/lib/packages/abiword.rb +11 -0
- data/lib/packages/amazon_mp3.rb +4 -0
- data/lib/packages/awstats.rb +16 -0
- data/lib/packages/base.rb +14 -0
- data/lib/packages/chrome.rb +12 -0
- data/lib/packages/cruisecontrol.rb +22 -0
- data/lib/packages/dependencies.rb +10 -0
- data/lib/packages/docky.rb +36 -0
- data/lib/packages/dotfiles.rb +26 -0
- data/lib/packages/file_roller.rb +12 -0
- data/lib/packages/finalise.rb +4 -0
- data/lib/packages/firefox.rb +4 -0
- data/lib/packages/gedit.rb +11 -0
- data/lib/packages/git.rb +4 -0
- data/lib/packages/gmate.rb +33 -0
- data/lib/packages/gnome.rb +10 -0
- data/lib/packages/gnumeric.rb +11 -0
- data/lib/packages/hosts.rb +13 -0
- data/lib/packages/load_machines.rb +38 -0
- data/lib/packages/monit.rb +10 -0
- data/lib/packages/mysql.rb +46 -0
- data/lib/packages/nginx.rb +22 -0
- data/lib/packages/nginx_logrotate.rb +26 -0
- data/lib/packages/openbox.rb +35 -0
- data/lib/packages/passenger.rb +14 -0
- data/lib/packages/passenger_nginx.rb +8 -0
- data/lib/packages/postfix.rb +10 -0
- data/lib/packages/questions.rb +5 -0
- data/lib/packages/rbenv.rb +27 -0
- data/lib/packages/rvm.rb +20 -0
- data/lib/packages/save_machines.rb +4 -0
- data/lib/packages/slim.rb +6 -0
- data/lib/packages/sqlserver.rb +5 -0
- data/lib/packages/subtle.rb +29 -0
- data/lib/packages/sudo_mods.rb +6 -0
- data/lib/packages/time.rb +6 -0
- data/lib/packages/time_daily.rb +5 -0
- data/lib/packages/timezone.rb +10 -0
- data/lib/packages/unison.rb +5 -0
- data/lib/packages/virtualbox.rb +11 -0
- data/lib/packages/virtualbox_guest.rb +7 -0
- data/lib/packages/webapps.rb +36 -0
- data/lib/template/Machinesfile +48 -0
- data/lib/template/certificates/example.com.crt +0 -0
- data/lib/template/certificates/example.com.key +0 -0
- data/lib/template/certificates/selfsigned.crt +14 -0
- data/lib/template/certificates/selfsigned.key +16 -0
- data/lib/template/config.yml +98 -0
- data/lib/template/logrotate/app.erb +10 -0
- data/lib/template/logrotate/nginx.erb +12 -0
- data/lib/template/machines.yml +179 -0
- data/lib/template/misc/awstats.conf.erb +7 -0
- data/lib/template/misc/ntp.conf +7 -0
- data/lib/template/monit/conf.d/delayed_job.erb +11 -0
- data/lib/template/monit/conf.d/mysql.erb +7 -0
- data/lib/template/monit/conf.d/nginx +5 -0
- data/lib/template/monit/conf.d/postfix +7 -0
- data/lib/template/monit/conf.d/ssh +6 -0
- data/lib/template/monit/conf.d/system.erb +14 -0
- data/lib/template/monit/monitrc.erb +10 -0
- data/lib/template/monit/upstart.conf +16 -0
- data/lib/template/mysql/dbmaster.cnf +7 -0
- data/lib/template/mysql/dbslave.cnf +3 -0
- data/lib/template/nginx/app_server.conf.erb +87 -0
- data/lib/template/nginx/nginx.conf.erb +46 -0
- data/lib/template/nginx/upstart.conf.erb +21 -0
- data/lib/template/packages/custom.rb +17 -0
- data/lib/template/packages/productivity.rb +18 -0
- data/lib/template/slim/themes/dark/background.jpg +0 -0
- data/lib/template/slim/themes/dark/panel.png +0 -0
- data/lib/template/slim/themes/dark/slim.theme +39 -0
- data/lib/template/users/phil/dotfiles/bash_aliases +45 -0
- data/lib/template/users/phil/dotfiles/config/Trolltech.conf +4 -0
- data/lib/template/users/phil/dotfiles/config/gtk-3.0/settings.ini +9 -0
- data/lib/template/users/phil/dotfiles/config/openbox/autostart.sh +14 -0
- data/lib/template/users/phil/dotfiles/config/openbox/rc.xml +482 -0
- data/lib/template/users/phil/dotfiles/config/terminator/config +10 -0
- data/lib/template/users/phil/dotfiles/fonts.conf +15 -0
- data/lib/template/users/phil/dotfiles/gitconfig +27 -0
- data/lib/template/users/phil/dotfiles/gtkrc-2.0 +16 -0
- data/lib/template/users/phil/dotfiles/local/share/applications/mimeapps.list +4 -0
- data/lib/template/users/phil/dotfiles/unison/default.prf +33 -0
- data/lib/template/users/www/authorized_keys +0 -0
- data/lib/template/users/www/dotfiles/bash_aliases +40 -0
- data/lib/template/webapps.yml +75 -0
- data/machines.gemspec +44 -0
- data/spec/acceptance/dev_machine_spec.rb +22 -0
- data/spec/lib/machines/app_settings_spec.rb +106 -0
- data/spec/lib/machines/checks_spec.rb +105 -0
- data/spec/lib/machines/cloud_machine_spec.rb +36 -0
- data/spec/lib/machines/command_spec.rb +184 -0
- data/spec/lib/machines/commandline_spec.rb +299 -0
- data/spec/lib/machines/configuration_spec.rb +61 -0
- data/spec/lib/machines/core_spec.rb +299 -0
- data/spec/lib/machines/database_spec.rb +51 -0
- data/spec/lib/machines/file_operations_spec.rb +124 -0
- data/spec/lib/machines/help_spec.rb +22 -0
- data/spec/lib/machines/installation_spec.rb +176 -0
- data/spec/lib/machines/log_command_spec.rb +16 -0
- data/spec/lib/machines/logger_spec.rb +70 -0
- data/spec/lib/machines/machinesfile_spec.rb +34 -0
- data/spec/lib/machines/questions_spec.rb +73 -0
- data/spec/lib/machines/services_spec.rb +26 -0
- data/spec/lib/machines/upload_spec.rb +86 -0
- data/spec/lib/packages/abiword_spec.rb +20 -0
- data/spec/lib/packages/amazon_mp3_spec.rb +17 -0
- data/spec/lib/packages/awstats_spec.rb +26 -0
- data/spec/lib/packages/base_spec.rb +21 -0
- data/spec/lib/packages/chrome_spec.rb +30 -0
- data/spec/lib/packages/cruisecontrol_spec.rb +33 -0
- data/spec/lib/packages/dependencies_spec.rb +20 -0
- data/spec/lib/packages/docky_spec.rb +32 -0
- data/spec/lib/packages/dotfiles_spec.rb +44 -0
- data/spec/lib/packages/file_roller_spec.rb +69 -0
- data/spec/lib/packages/firefox_spec.rb +16 -0
- data/spec/lib/packages/gedit_spec.rb +20 -0
- data/spec/lib/packages/git_spec.rb +16 -0
- data/spec/lib/packages/gmate_spec.rb +39 -0
- data/spec/lib/packages/gnome_spec.rb +22 -0
- data/spec/lib/packages/gnumeric_spec.rb +21 -0
- data/spec/lib/packages/hosts_spec.rb +41 -0
- data/spec/lib/packages/load_machines_spec.rb +118 -0
- data/spec/lib/packages/monit_spec.rb +34 -0
- data/spec/lib/packages/mysql_spec.rb +69 -0
- data/spec/lib/packages/nginx_logrotate_spec.rb +80 -0
- data/spec/lib/packages/nginx_spec.rb +46 -0
- data/spec/lib/packages/openbox_spec.rb +41 -0
- data/spec/lib/packages/passenger_nginx_spec.rb +20 -0
- data/spec/lib/packages/passenger_spec.rb +26 -0
- data/spec/lib/packages/postfix_spec.rb +19 -0
- data/spec/lib/packages/questions_spec.rb +29 -0
- data/spec/lib/packages/rbenv_spec.rb +32 -0
- data/spec/lib/packages/rvm_spec.rb +31 -0
- data/spec/lib/packages/save_machines_spec.rb +51 -0
- data/spec/lib/packages/slim_spec.rb +22 -0
- data/spec/lib/packages/sqlserver_spec.rb +17 -0
- data/spec/lib/packages/timezone_spec.rb +27 -0
- data/spec/lib/packages/unison_spec.rb +17 -0
- data/spec/lib/packages/virtualbox_guest_spec.rb +25 -0
- data/spec/lib/packages/virtualbox_spec.rb +23 -0
- data/spec/lib/packages/webapps_spec.rb +70 -0
- data/spec/spec_helper.rb +103 -0
- data/spec/support/coverage.rb +8 -0
- data/spec/support/fake_out.rb +22 -0
- data/spec/support/fakefs_additions.rb +10 -0
- data/spec/support/minitest.rb +69 -0
- data/spec/support/vm_control.rb +54 -0
- data/tmp/.gitkeep +0 -0
- metadata +581 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Machines
|
|
2
|
+
module CloudMachine
|
|
3
|
+
def connect_to_cloud
|
|
4
|
+
begin
|
|
5
|
+
require 'fog'
|
|
6
|
+
rescue LoadError
|
|
7
|
+
say 'fog gem required to use cloud features.'
|
|
8
|
+
say 'Please "gem install fog".'
|
|
9
|
+
raise
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Fog.credential = 'machines_key'
|
|
13
|
+
options = symbolize_keys($conf.cloud.to_hash)
|
|
14
|
+
options.merge!(:region => $conf.machine.cloud.region)
|
|
15
|
+
$conf.cloud.connection = Fog::Compute.new(options)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create_server
|
|
19
|
+
server = $conf.cloud.connection.servers.create(
|
|
20
|
+
:private_key_path => $conf.machine.cloud.private_key_path,
|
|
21
|
+
:public_key_path => $conf.machine.cloud.public_key_path,
|
|
22
|
+
:username => $conf.machine.cloud.username,
|
|
23
|
+
:flavor_id => $conf.machine.cloud.flavor_id,
|
|
24
|
+
:image_id => $conf.machine.cloud.image_id)
|
|
25
|
+
server.wait_for { ready? }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def symbolize_keys hash
|
|
29
|
+
hash.inject({}){|new_hash, (k, v)| new_hash[k.to_sym] = v; new_hash }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require 'machines/logger'
|
|
2
|
+
|
|
3
|
+
module Machines
|
|
4
|
+
class Command
|
|
5
|
+
class << self
|
|
6
|
+
attr_accessor :file, :debug, :console
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
attr_accessor :command, :check
|
|
10
|
+
|
|
11
|
+
def self.scp= scp
|
|
12
|
+
@@scp = scp
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.ssh= ssh
|
|
16
|
+
@@ssh = ssh
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.ssh
|
|
20
|
+
@@ssh
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.scp
|
|
24
|
+
@@scp
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def initialize(command, check)
|
|
28
|
+
@command = command
|
|
29
|
+
@check = check
|
|
30
|
+
@sudo = false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def use_sudo
|
|
34
|
+
@sudo = 'sudo'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def run
|
|
38
|
+
process {Command.file.log @@ssh.exec! wrap_in_export_and_sudo(@command)}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def info
|
|
42
|
+
("%-6s " % (@sudo ? 'SUDO' : 'RUN')) + command
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
protected
|
|
46
|
+
def progress
|
|
47
|
+
"%3d%% " % (($conf.commands.index(self) + 1) / $conf.commands.count.to_f * 100).round
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def process &block
|
|
51
|
+
Command.console.log progress + info, :newline => ($conf.log_only || false)
|
|
52
|
+
Command.file.log info, :color => :highlight
|
|
53
|
+
unless $conf.log_only
|
|
54
|
+
begin
|
|
55
|
+
yield
|
|
56
|
+
result = @@ssh.exec!(wrap_in_export_and_sudo(@check))
|
|
57
|
+
result = check_result(result || '')
|
|
58
|
+
color = color_for(result)
|
|
59
|
+
Command.file.log result, :color => color
|
|
60
|
+
Command.console.log progress + info, :color => color
|
|
61
|
+
rescue Exception => e
|
|
62
|
+
Command.console.log(progress + info, :color => :failure) rescue nil
|
|
63
|
+
Command.file.log(e.to_s, :color => :failure) rescue nil
|
|
64
|
+
raise e
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def wrap_in_export_and_sudo command
|
|
70
|
+
command = "export TERM=linux && #{command}"
|
|
71
|
+
echo_password = "echo #{$conf.password} | " if $conf.password
|
|
72
|
+
command = "#{echo_password}sudo -S bash -c '#{command}'" if @sudo
|
|
73
|
+
Command.debug.log command
|
|
74
|
+
command
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def check_result result
|
|
78
|
+
result.scan(/CHECK PASSED|CHECK FAILED/).first || 'NOT CHECKED'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def color_for result
|
|
82
|
+
{'NOT CHECKED' => :warning, 'CHECK FAILED' => :failure, 'CHECK PASSED' => :success}[result]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
module Machines
|
|
2
|
+
module Commandline
|
|
3
|
+
# Loads Machinesfile, opens an SCP connection and runs all commands and file uploads
|
|
4
|
+
def build options
|
|
5
|
+
$conf.machine_name = options.shift
|
|
6
|
+
$conf.task = options.shift
|
|
7
|
+
init
|
|
8
|
+
load_machinesfile
|
|
9
|
+
|
|
10
|
+
task $conf.task.to_sym if $conf.task
|
|
11
|
+
|
|
12
|
+
ssh_options = {:paranoid => false}
|
|
13
|
+
if $conf.machine.cloud
|
|
14
|
+
username = $conf.machine.cloud.username
|
|
15
|
+
ssh_options[:keys] = [$conf.machine.cloud.private_key_path]
|
|
16
|
+
else
|
|
17
|
+
username = $conf.machine.user
|
|
18
|
+
ssh_options[:password] = $conf.password
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
if $conf.log_only
|
|
22
|
+
$conf.commands.each do |command|
|
|
23
|
+
command.run
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
Kernel.trap("INT") { prepare_to_exit }
|
|
27
|
+
begin
|
|
28
|
+
Command.ssh = Net::SSH.start $conf.machine.address, username, ssh_options
|
|
29
|
+
Command.scp = Net::SCP.new(Command.ssh)
|
|
30
|
+
$conf.commands.each do |command|
|
|
31
|
+
command.run
|
|
32
|
+
Command.file.flush
|
|
33
|
+
exit if $exit_requested
|
|
34
|
+
end
|
|
35
|
+
ensure
|
|
36
|
+
Command.ssh.close
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def dryrun options
|
|
42
|
+
$conf.log_only = true
|
|
43
|
+
build options
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Execute a given command e.g. dryrun, build, generate, htpasswd, packages, override, tasks
|
|
47
|
+
def execute(options)
|
|
48
|
+
help = Help.new
|
|
49
|
+
action = options.shift
|
|
50
|
+
if help.actions.include?(action)
|
|
51
|
+
action = 'generate' if action == 'new'
|
|
52
|
+
send action, options
|
|
53
|
+
else
|
|
54
|
+
say help.syntax
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def generate options
|
|
59
|
+
dir = options.first || './'
|
|
60
|
+
if File.exists? dir
|
|
61
|
+
confirm = ask "Overwrite '#{dir}' (y/n)? "
|
|
62
|
+
return unless confirm.downcase == 'y'
|
|
63
|
+
end
|
|
64
|
+
FileUtils.cp_r(File.join($conf.application_dir, 'template', '/.'), dir)
|
|
65
|
+
FileUtils.mkdir_p(File.join(dir, 'packages'))
|
|
66
|
+
say "Project created at #{dir}/"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def htpasswd options
|
|
70
|
+
path = File.join($conf.webserver, 'conf', 'htpasswd')
|
|
71
|
+
say "Generate BasicAuth password and add to #{path}"
|
|
72
|
+
username = ask('Username: ')
|
|
73
|
+
password = enter_password 'users'
|
|
74
|
+
|
|
75
|
+
crypted_pass = password.crypt(WEBrick::Utils.random_string(2))
|
|
76
|
+
FileUtils.mkdir_p File.dirname(path)
|
|
77
|
+
File.open(path, 'a') {|file| file.puts "#{username}:#{crypted_pass}" }
|
|
78
|
+
say "Password encrypted and added to #{path}"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def init
|
|
82
|
+
$exit_requested = false
|
|
83
|
+
$conf.passwords = []
|
|
84
|
+
$conf.commands = []
|
|
85
|
+
$conf.tasks = {}
|
|
86
|
+
$conf.load('config.yml')
|
|
87
|
+
|
|
88
|
+
Command.file ||= Machines::Logger.new File.open('log/output.log', 'w')
|
|
89
|
+
Command.debug ||= Machines::Logger.new File.open('log/debug.log', 'w')
|
|
90
|
+
Command.console ||= Machines::Logger.new STDOUT, :truncate => true
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def load_machinesfile
|
|
94
|
+
eval File.read('Machinesfile'), nil, "eval: Machinesfile"
|
|
95
|
+
rescue LoadError => e
|
|
96
|
+
if e.message =~ /Machinesfile/
|
|
97
|
+
raise LoadError, "Machinesfile does not exist. Use `machines new <DIR>` to create a template."
|
|
98
|
+
else
|
|
99
|
+
raise
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def packages notused
|
|
104
|
+
say 'Default packages'
|
|
105
|
+
Dir[File.join($conf.application_dir, 'packages', '**/*.rb')].each do |package|
|
|
106
|
+
say " * #{File.basename(package, '.rb')}"
|
|
107
|
+
end
|
|
108
|
+
say ''
|
|
109
|
+
|
|
110
|
+
say 'Project packages'
|
|
111
|
+
Dir[File.join('packages', '**/*.rb')].each do |package|
|
|
112
|
+
say " * #{File.basename(package, '.rb')}"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def override package
|
|
117
|
+
package = package.first
|
|
118
|
+
destination = File.join('packages', "#{package}.rb")
|
|
119
|
+
answer = File.exists?(destination) ? ask('Project package already exists. Overwrite? (y/n)') : 'y'
|
|
120
|
+
if answer == 'y'
|
|
121
|
+
source = File.join($conf.application_dir, 'packages', "#{package}.rb")
|
|
122
|
+
FileUtils.cp(source, destination)
|
|
123
|
+
say "Package copied to #{destination}"
|
|
124
|
+
else
|
|
125
|
+
say 'Aborted.'
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def tasks
|
|
130
|
+
$conf.log_only = true
|
|
131
|
+
init
|
|
132
|
+
load_machinesfile
|
|
133
|
+
say 'Tasks'
|
|
134
|
+
$conf.tasks.each do |task_name, settings|
|
|
135
|
+
say " %-20s #{settings[:description]}" % task_name
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
def prepare_to_exit
|
|
141
|
+
exit if $exit_requested
|
|
142
|
+
$exit_requested = true
|
|
143
|
+
Command.console.log("\nEXITING after current command completes...", :color => :warning)
|
|
144
|
+
Command.console.log("(Press again to terminate immediately)...", :color => :warning)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Machines
|
|
2
|
+
module Configuration
|
|
3
|
+
# Add a new user
|
|
4
|
+
# (uses the lowlevel useradd so doesn't set a password unless specified)
|
|
5
|
+
# @param [String] login User name to create
|
|
6
|
+
# @param [Hash] options
|
|
7
|
+
# @option options [String] :password
|
|
8
|
+
# @option options [Boolean] :admin Adds the user to the admin group when true
|
|
9
|
+
def add_user login, options = {}
|
|
10
|
+
password = "-p #{`openssl passwd #{options[:password]}`.gsub("\n", '')} " if options[:password]
|
|
11
|
+
admin = "-G admin " if options[:admin]
|
|
12
|
+
Command.new(
|
|
13
|
+
"useradd -s /bin/bash -d /home/#{login} -m #{password}#{admin}#{login}",
|
|
14
|
+
check_dir("/home/#{login}")
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Add an existing user to a secondary group
|
|
19
|
+
# @param [Hash] options
|
|
20
|
+
# @option options [String] :user The user to add
|
|
21
|
+
# @option options [String] :to Adds an existing user to the specified group
|
|
22
|
+
def add options
|
|
23
|
+
required_options options, [:user, :to]
|
|
24
|
+
Command.new("usermod -a -G #{options[:to]} #{options[:user]}", check_command("groups #{options[:user]}", options[:to]))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Sets gconf key value pairs
|
|
28
|
+
# @param [Hash] options One or many key/value pairs to set
|
|
29
|
+
def configure options
|
|
30
|
+
options.map do |key, value|
|
|
31
|
+
types = {String => 'string', Fixnum => 'int', TrueClass => 'bool',
|
|
32
|
+
FalseClass => 'bool', Float => 'float', Array => 'list --list-type=string'}
|
|
33
|
+
type = types[value.class]
|
|
34
|
+
raise 'Invalid type for configure' unless type
|
|
35
|
+
value = value.to_json if value.is_a?(Array)
|
|
36
|
+
value = %("#{value}") if type == 'string'
|
|
37
|
+
check = "gconftool-2 --get \"#{key}\" | grep #{value} #{echo_result}"
|
|
38
|
+
Command.new("gconftool-2 --set \"#{key}\" --type #{type} #{value}", check)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Removes a user, home and any other related files
|
|
43
|
+
# @param [String] login User name to remove
|
|
44
|
+
def del_user login
|
|
45
|
+
Command.new("deluser #{login} --remove-home -q", check_file('/home/login', false))
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module Machines
|
|
2
|
+
module Core
|
|
3
|
+
# If a block is given, store the task, log it and run it
|
|
4
|
+
# If no block is given, sets commands to only those of the specified task so they can be run standalone
|
|
5
|
+
# @param [Symbol] name Name of the task
|
|
6
|
+
# @param [String] description Describe the task
|
|
7
|
+
# @param [Hash] options
|
|
8
|
+
# @option options [Symbol, Array] :if Dependent tasks that must already have been added for this task to be added
|
|
9
|
+
def task name, description = nil, options = {}, &block
|
|
10
|
+
if block
|
|
11
|
+
dependencies = [options[:if]].flatten
|
|
12
|
+
return if options[:if] && (dependencies - $conf.tasks.keys).any?
|
|
13
|
+
store_task name, description, &block
|
|
14
|
+
$conf.commands << LogCommand.new(name, description)
|
|
15
|
+
yield
|
|
16
|
+
else
|
|
17
|
+
$conf.commands = []
|
|
18
|
+
$conf.tasks[name][:block].call
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def store_task name, description, &block
|
|
23
|
+
$conf.tasks[name] = {:description => description, :block => block}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def list_tasks
|
|
27
|
+
$conf.tasks.each do |name, task|
|
|
28
|
+
say " #{"%-20s" % name}#{task[:description]}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def generate_password
|
|
33
|
+
WEBrick::Utils.random_string(20)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Only executes the code if $conf parameters match what is given in args
|
|
37
|
+
def only options, &block
|
|
38
|
+
yield if matched(options)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Does not execute the code if $conf parameters match what is given in args
|
|
42
|
+
def except options, &block
|
|
43
|
+
yield unless matched(options)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def matched options
|
|
47
|
+
options.each do |key, value|
|
|
48
|
+
value = value.is_a?(Array) ? value.map{|o| o.to_s } : value.to_s
|
|
49
|
+
if $conf[key].is_a?(Array)
|
|
50
|
+
values = $conf[key].map{|o| o.to_s }
|
|
51
|
+
if value.is_a?(Array)
|
|
52
|
+
return unless values.reject{ |symbol| !value.include?(symbol.to_s) }.any?
|
|
53
|
+
else
|
|
54
|
+
return unless values.include?(value)
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
if value.is_a?(Array)
|
|
58
|
+
return unless value.include?($conf[key].to_s)
|
|
59
|
+
else
|
|
60
|
+
return unless value == $conf[key].to_s
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Queue up command(s) to run remotely
|
|
68
|
+
# @param [Array] commands Command(s) to run.
|
|
69
|
+
# If first command is a string it creates a Command object using the first two strings as command and check
|
|
70
|
+
def run *commands
|
|
71
|
+
commands = command_from_string(commands)
|
|
72
|
+
$conf.commands += commands.flatten
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Queue up command(s) using SUDO to run remotely
|
|
76
|
+
# @param [Array] commands Command(s) to run
|
|
77
|
+
def sudo *commands
|
|
78
|
+
commands = command_from_string commands
|
|
79
|
+
commands.flatten.each do |command|
|
|
80
|
+
if command.is_a?(Upload)
|
|
81
|
+
temp_path = "/tmp/#{File.basename(command.remote)}"
|
|
82
|
+
dir_suffix = command.local.is_a?(String) && File.directory?(command.local) ? '/.' : ''
|
|
83
|
+
remote_dest = command.remote
|
|
84
|
+
command.remote = temp_path
|
|
85
|
+
command.check = check_file(temp_path)
|
|
86
|
+
run command
|
|
87
|
+
sudo copy(temp_path + dir_suffix, remote_dest)
|
|
88
|
+
run remove temp_path
|
|
89
|
+
else
|
|
90
|
+
command.use_sudo
|
|
91
|
+
run command
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Upload a file or folder using SCP
|
|
97
|
+
# Can be used with sudo or run
|
|
98
|
+
# @param [String] local_source File or folder on the local machine
|
|
99
|
+
# @param [String] remote_dest Folder on the remote machine to copy to
|
|
100
|
+
# upload 'source_dir', '~' #=> creates source_dir/subdir as ~/subdir
|
|
101
|
+
def upload local_source, remote_dest
|
|
102
|
+
Upload.new(local_source, remote_dest, check_file(remote_dest))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Validate some methods that require certain options
|
|
106
|
+
def required_options options, required
|
|
107
|
+
required.each do |option|
|
|
108
|
+
raise ArgumentError, "Missing option '#{option}'. Check trace for location of the problem." unless options[option]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def command_from_string commands
|
|
113
|
+
commands.first.is_a?(String) ? [Command.new(commands[0], commands[1])] : commands
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Machines
|
|
2
|
+
module Database
|
|
3
|
+
# Write the database.yml file from webapps.yml
|
|
4
|
+
# @param [AppBuilder] app
|
|
5
|
+
def write_database_yml app
|
|
6
|
+
yml = {$conf.environment.to_s => {
|
|
7
|
+
'adapter' => 'mysql',
|
|
8
|
+
'database' => app.database || app.name,
|
|
9
|
+
'username' => app.username || app.name,
|
|
10
|
+
'password' => app.password,
|
|
11
|
+
'host' => $conf.db_server.address,
|
|
12
|
+
'encoding' => 'utf8'}}.to_yaml
|
|
13
|
+
write yml, :to => File.join(app.path, 'shared/config/database.yml'), :name => 'database.yml'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module Machines
|
|
2
|
+
module FileOperations
|
|
3
|
+
# Add a line of text to the end of a file unless it already exists
|
|
4
|
+
# @param [String] text Text to add
|
|
5
|
+
# @param [Hash] options
|
|
6
|
+
# @option options [String] :to File to append to
|
|
7
|
+
def append text, options
|
|
8
|
+
text = text.gsub(/([\\$"`])/, '\\\\\1')
|
|
9
|
+
Command.new("grep \"#{text}\" #{options[:to]} || echo \"#{text}\" >> #{options[:to]}", check_string(text, options[:to]))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Change permissions of a path
|
|
13
|
+
# @param [String, Integer] mode chmod permissions to set
|
|
14
|
+
# @param [String] path Path to set
|
|
15
|
+
def chmod mode, path
|
|
16
|
+
Command.new("chmod #{mode} #{path}", check_perms(mode, path))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Change ownership of a path
|
|
20
|
+
# @param [String] user sets user and group unless user:group is specified
|
|
21
|
+
# @param [String] path Path to set
|
|
22
|
+
# @param [Hash] options
|
|
23
|
+
# @option options [String] :recursive Chowns recursively if true
|
|
24
|
+
def chown user, path, options = {}
|
|
25
|
+
recursive = '-R ' if options[:recursive]
|
|
26
|
+
user = "#{user}:#{user}" unless user.index(':')
|
|
27
|
+
Command.new("chown #{recursive}#{user} #{path}", check_owner(user, path))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Copy a remote file or folder (will overwrite)
|
|
31
|
+
# @param [String] from Existing path
|
|
32
|
+
# @param [String] to Path to copy to
|
|
33
|
+
def copy from, to
|
|
34
|
+
Command.new("cp -rf #{from} #{to}", check_file(to))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Write a file from an ERB template
|
|
38
|
+
# @param [String] erb_path Path to the ERB file to process
|
|
39
|
+
# @param [Hash] options
|
|
40
|
+
# @option options [AppBuilder] :settings Contains the settings as OpenStruct method calls for calling from the template
|
|
41
|
+
# @option options [String] :to File to write to
|
|
42
|
+
def create_from erb_path, options
|
|
43
|
+
erb = ERB.new(File.read(erb_path), nil, '<>')
|
|
44
|
+
binding = options[:settings] ? options[:settings].get_binding : nil
|
|
45
|
+
options[:name] = erb_path
|
|
46
|
+
write erb.result(binding), options
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Add a symlink
|
|
50
|
+
# @param [String] target Existing path to link
|
|
51
|
+
# @param [String] link_name path name for the link
|
|
52
|
+
def link target, link_name
|
|
53
|
+
Command.new("ln -sf #{target} #{link_name}", check_link(link_name))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Create a path or paths on the remote host (Uses -p to be safe and create full path)
|
|
57
|
+
# @param [String, Array] dirs A single path, multiple paths or array of paths to create
|
|
58
|
+
def mkdir *dirs
|
|
59
|
+
dirs.flatten.map do |dir|
|
|
60
|
+
Command.new("mkdir -p #{dir}", check_dir(dir))
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Rename a remote file or folder
|
|
65
|
+
# @param [String] oldname Existing filename
|
|
66
|
+
# @param [String] newname Rename to this =
|
|
67
|
+
def rename oldname, newname
|
|
68
|
+
Command.new("mv -f #{oldname} #{newname}", check_file(newname))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Remove a remote file or folder
|
|
72
|
+
# @param [String] file or folder to remove (uses rm with -rf which ignores non-existent files and is recursive)
|
|
73
|
+
def remove file
|
|
74
|
+
Command.new("rm -rf #{file}", check_file(file, false))
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Take off the version numbers from a path name
|
|
78
|
+
# @param [String] name Name of the path to rename
|
|
79
|
+
def remove_version_info name
|
|
80
|
+
Command.new("find . -maxdepth 1 -name \"#{name}*\" -a -type d | xargs -I xxx mv xxx #{name}", check_file(name))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Replace some text in a file
|
|
84
|
+
# @param [String] regex The expression to search for
|
|
85
|
+
# @param [Hash] options
|
|
86
|
+
# @option options [String] :with Text to use as the replacement
|
|
87
|
+
# @option options [String] :in Filename to replace text in
|
|
88
|
+
def replace regex, options
|
|
89
|
+
required_options options, [:with, :in]
|
|
90
|
+
with = options[:with].gsub(/([\n\/\\$"`])/, '\\\\\1')
|
|
91
|
+
Command.new("sed -i \"s/#{regex}/#{with}/\" #{options[:in]}", check_string(with, options[:in]))
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# (Over)write a file with the specified content
|
|
95
|
+
# @param [String] text Text to add
|
|
96
|
+
# @param [Hash] options
|
|
97
|
+
# @option options [String] :to File to write to
|
|
98
|
+
# @option options [String] :name Give the buffer a displayable name (e.g. when generated from a template)
|
|
99
|
+
def write text, options
|
|
100
|
+
Upload.new(NamedBuffer.new(options[:name], text), options[:to], check_string(text, options[:to]))
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Machines
|
|
2
|
+
class Help
|
|
3
|
+
def initialize
|
|
4
|
+
@actions = {
|
|
5
|
+
'htpasswd' => 'Generates basic auth in webserver/conf/htpasswd',
|
|
6
|
+
'new <DIR>' => 'Generates an example machines project in DIR',
|
|
7
|
+
'dryrun <machine>' => 'Logs commands but does not run them',
|
|
8
|
+
'tasks' => 'Lists the available tasks',
|
|
9
|
+
'build <machine> [task]' => 'Builds your chosen machine. Optionally, build just one task',
|
|
10
|
+
'list' => 'Lists the available machines',
|
|
11
|
+
'packages' => 'Lists the available packages',
|
|
12
|
+
'override <PACKAGE>' => 'Copies the default package into project/packages so it can be edited/overidden'
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def actions
|
|
17
|
+
@actions.keys.map{|key| key.gsub(/ .*/, '')}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def syntax
|
|
21
|
+
<<HELP
|
|
22
|
+
machines v#{Machines::VERSION} - Ubuntu/Ruby configuration tool.
|
|
23
|
+
machines COMMAND
|
|
24
|
+
COMMAND can be:
|
|
25
|
+
#{@actions.map{|action, help| " %-25s#{help}" % action}.join("\n")}
|
|
26
|
+
HELP
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|