ridoku 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/AUTHORS +3 -0
- data/Gemfile +24 -0
- data/Gemfile.lock +45 -0
- data/LICENSE.txt +23 -0
- data/README.md +271 -0
- data/Rakefile +1 -0
- data/bin/rid +3 -0
- data/bin/ridoku +350 -0
- data/lib/helpers.rb +13 -0
- data/lib/io-colorize.rb +35 -0
- data/lib/options.rb +142 -0
- data/lib/ridoku.rb +11 -0
- data/lib/ridoku/backup.rb +393 -0
- data/lib/ridoku/base.rb +717 -0
- data/lib/ridoku/config_wizard.rb +195 -0
- data/lib/ridoku/cook.rb +103 -0
- data/lib/ridoku/create.rb +101 -0
- data/lib/ridoku/cron.rb +227 -0
- data/lib/ridoku/db.rb +235 -0
- data/lib/ridoku/defaults.rb +68 -0
- data/lib/ridoku/deploy.rb +157 -0
- data/lib/ridoku/domain.rb +124 -0
- data/lib/ridoku/dump.rb +132 -0
- data/lib/ridoku/env.rb +118 -0
- data/lib/ridoku/list.rb +168 -0
- data/lib/ridoku/log.rb +77 -0
- data/lib/ridoku/maintenance.rb +76 -0
- data/lib/ridoku/packages.rb +93 -0
- data/lib/ridoku/rails_defaults.rb +160 -0
- data/lib/ridoku/run.rb +137 -0
- data/lib/ridoku/service.rb +158 -0
- data/lib/ridoku/services/postgres.rb +77 -0
- data/lib/ridoku/services/rabbitmq.rb +48 -0
- data/lib/ridoku/version.rb +5 -0
- data/lib/ridoku/workers.rb +138 -0
- data/ridoku.gemspec +32 -0
- metadata +211 -0
data/lib/ridoku/log.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#
|
2
|
+
# Command: log
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'ridoku/base'
|
6
|
+
|
7
|
+
module Ridoku
|
8
|
+
register :log
|
9
|
+
|
10
|
+
class Log < Base
|
11
|
+
attr_accessor :environment
|
12
|
+
|
13
|
+
def run
|
14
|
+
command = Base.config[:command]
|
15
|
+
sub_command = (command.length > 0 && command[1]) || nil
|
16
|
+
|
17
|
+
case sub_command
|
18
|
+
when 'unicorn', nil
|
19
|
+
unicorn_log
|
20
|
+
when 'nginx'
|
21
|
+
nginx_log
|
22
|
+
when 'all'
|
23
|
+
all_logs
|
24
|
+
else
|
25
|
+
print_log_help
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def unicorn_log_command
|
32
|
+
Base.fetch_app
|
33
|
+
|
34
|
+
lines = "#{Base.config[:lines] || 250}"
|
35
|
+
dir = "/srv/www/#{Base.app[:shortname]}/shared/log"
|
36
|
+
"for f in #{dir}/*.log; do echo "\
|
37
|
+
"#{$stdout.colorize("Log #{lines}: $f; "\
|
38
|
+
"echo #{'=' * 80}", [:bold])};"\
|
39
|
+
"tail -#{lines} $f; echo; done"
|
40
|
+
end
|
41
|
+
|
42
|
+
def line_break(title)
|
43
|
+
"#{'=' * 80}\n==== #{title}\n#{'=' * 80}\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
def unicorn_log
|
47
|
+
$stdout.puts $stdout.colorize(line_break('Unicorn Logs'), [:bold, :green])
|
48
|
+
system(Ridoku::Run.command(unicorn_log_command, false))
|
49
|
+
end
|
50
|
+
|
51
|
+
def nginx_log
|
52
|
+
$stdout.puts $stdout.colorize(line_break('Nginx Logs'), [:bold, :green])
|
53
|
+
system(Ridoku::Run.command('tail -1000 /var/log/nginx/error.log'))
|
54
|
+
end
|
55
|
+
|
56
|
+
def all_logs
|
57
|
+
nginx_log
|
58
|
+
unicorn_log
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def print_log_help
|
63
|
+
$stderr.puts <<-EOF
|
64
|
+
Command: log
|
65
|
+
|
66
|
+
Log the specified command on an instance:
|
67
|
+
log[:unicorn] print unicorn logs for the specified app and instance
|
68
|
+
log:nginx print nginx logs for the specified app and instance
|
69
|
+
log:all print all logs for specified instance and app to commandline
|
70
|
+
|
71
|
+
examples:
|
72
|
+
$ ridoku log --mukujara
|
73
|
+
|
74
|
+
EOF
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#
|
2
|
+
# Command: maintenance
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'ridoku/base'
|
6
|
+
|
7
|
+
module Ridoku
|
8
|
+
register :maintenance
|
9
|
+
|
10
|
+
class Maintenance < Base
|
11
|
+
attr_accessor :app
|
12
|
+
|
13
|
+
def run
|
14
|
+
clist = Base.config[:command]
|
15
|
+
command = clist.shift
|
16
|
+
sub_command = clist.shift
|
17
|
+
|
18
|
+
case sub_command
|
19
|
+
when 'on'
|
20
|
+
maintenance(true)
|
21
|
+
when 'off'
|
22
|
+
maintenance(false)
|
23
|
+
when 'status', nil
|
24
|
+
status
|
25
|
+
else
|
26
|
+
print_maintenance_help
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def maintenance(maint)
|
33
|
+
Base.fetch_stack
|
34
|
+
Base.fetch_app
|
35
|
+
|
36
|
+
Base.custom_json['deploy'][Base.app[:shortname]]['maintenance'] = maint
|
37
|
+
Base.save_stack
|
38
|
+
|
39
|
+
Ridoku::Cook.cook_recipe_on_layers('deploy::maintenance', ['rails-app'],
|
40
|
+
deploy: {
|
41
|
+
Base.app[:shortname] => {
|
42
|
+
application_type: 'rails'
|
43
|
+
}
|
44
|
+
}
|
45
|
+
)
|
46
|
+
status
|
47
|
+
end
|
48
|
+
|
49
|
+
def status
|
50
|
+
Base.fetch_stack
|
51
|
+
Base.fetch_app
|
52
|
+
|
53
|
+
$stdout.print 'Maintenance: '
|
54
|
+
|
55
|
+
app_json = Base.custom_json['deploy'][Base.app[:shortname]]
|
56
|
+
|
57
|
+
if app_json.key?('maintenance')
|
58
|
+
maint = (app_json['maintenance'] == true)
|
59
|
+
$stdout.puts $stdout.colorize((maint ? 'on' : 'off'),
|
60
|
+
[:bold, (maint ? :red : :green)])
|
61
|
+
else
|
62
|
+
$stdout.puts $stdout.colorize('off', :green)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def print_maintenance_help
|
67
|
+
$stderr.puts <<-EOF
|
68
|
+
Command: maintenance
|
69
|
+
|
70
|
+
Set maintenance mode on the specific applications:
|
71
|
+
maintenance:on Turn on maintenance mode for all application instances.
|
72
|
+
maintenance:off Turn off maintenance mode for all application instances.
|
73
|
+
EOF
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
#
|
2
|
+
# Command: packages
|
3
|
+
# Description: List/Modify the current apps configuration.
|
4
|
+
# packages - lists the key value pairs
|
5
|
+
# packages:add PACKAGE [...]
|
6
|
+
# packages:delete KEY
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'ridoku/base'
|
10
|
+
|
11
|
+
module Ridoku
|
12
|
+
register :packages
|
13
|
+
|
14
|
+
class Packages < Base
|
15
|
+
|
16
|
+
def run
|
17
|
+
command = Base.config[:command]
|
18
|
+
sub_command = (command.length > 0 && command[1]) || nil
|
19
|
+
|
20
|
+
case sub_command
|
21
|
+
when 'list', nil
|
22
|
+
list
|
23
|
+
when 'set', 'add'
|
24
|
+
set
|
25
|
+
when 'delete', 'remove', 'rm'
|
26
|
+
delete
|
27
|
+
else
|
28
|
+
print_package_help
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def print_package_help
|
35
|
+
$stderr.puts <<-EOF
|
36
|
+
Command: packages
|
37
|
+
|
38
|
+
List/Modify the current layer's package dependencies.
|
39
|
+
packages lists the key value pairs
|
40
|
+
packages:set PACKAGE [...]
|
41
|
+
packages:delete PACKAGE [...]
|
42
|
+
|
43
|
+
#{$stderr.colorize('Warning:', [:bold, :red])} Currently, this is limited by Opsworks to 10 packages.
|
44
|
+
EOF
|
45
|
+
end
|
46
|
+
|
47
|
+
def list
|
48
|
+
Base.fetch_layer(Base.config[:layer] || 'rails-app')
|
49
|
+
|
50
|
+
if Base.layers.length == 0
|
51
|
+
$stdout.puts 'No Layers Selected!'
|
52
|
+
|
53
|
+
else
|
54
|
+
max = 0
|
55
|
+
Base.layers.each do |layer|
|
56
|
+
short = $stdout.colorize(layer[:shortname], :bold)
|
57
|
+
max = short.length if max < short.length
|
58
|
+
end
|
59
|
+
|
60
|
+
Base.layers.each do |layer|
|
61
|
+
fmt = "%#{max}s"
|
62
|
+
shortname = sprintf(fmt, $stdout.colorize(layer[:shortname], :bold))
|
63
|
+
$stdout.puts "[#{shortname}] #{layer[:name]}: " +
|
64
|
+
"#{$stdout.colorize('No Packages Selected', :red) if
|
65
|
+
layer[:packages].length == 0}"
|
66
|
+
layer[:packages].each do |pack|
|
67
|
+
$stdout.puts " #{$stdout.colorize(pack, :green)}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def set
|
74
|
+
Base.fetch_layer(Base.config[:layer] || 'rails-app')
|
75
|
+
|
76
|
+
ARGV.each do |package|
|
77
|
+
# $stdout.puts "#{update && 'Updating' || 'Adding'}: #{key} as '#{value}'"
|
78
|
+
end
|
79
|
+
|
80
|
+
# Base.save_layer(layer, :packages)
|
81
|
+
end
|
82
|
+
|
83
|
+
def delete
|
84
|
+
Base.fetch_layer(Base.config[:layer] || 'rails-app')
|
85
|
+
|
86
|
+
ARGV.each do |package|
|
87
|
+
# $stdout.puts "Deleting key: #{key}, '#{value}'"
|
88
|
+
end
|
89
|
+
|
90
|
+
# Base.save_layer(layer, :packages)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
|
2
|
+
require 'ridoku/defaults'
|
3
|
+
|
4
|
+
module Ridoku
|
5
|
+
class RailsDefaults < ClassProperties
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
|
9
|
+
self.warnings = {}.tap do |warn|
|
10
|
+
warn[:app_source] = <<-EOA
|
11
|
+
The App Source is the repository which you wish to pull your application
|
12
|
+
from. 'Type' should be 'git','subversion', etc. 'Url' should be the
|
13
|
+
'git@github:user/repo' url (or appropriate repository URL). 'SSH Key'
|
14
|
+
should be a Private key associated with the repository you pull from.
|
15
|
+
EOA
|
16
|
+
|
17
|
+
warn[:domains] = <<-EOB
|
18
|
+
Domains this server should respond to (used for the HTTP server config).
|
19
|
+
Separate each domain with a ':' or '|'.
|
20
|
+
EOB
|
21
|
+
end
|
22
|
+
|
23
|
+
self.required = {
|
24
|
+
stack: {
|
25
|
+
service_role_arn: :string,
|
26
|
+
default_instance_profile_arn: :string,
|
27
|
+
# attributes: Color: ?,
|
28
|
+
custom_cookbooks_source: { ssh_key: :optional }
|
29
|
+
},
|
30
|
+
layer: {
|
31
|
+
loadbalance: {
|
32
|
+
attributes: {
|
33
|
+
haproxy_stats_password: :string,
|
34
|
+
haproxy_stats_user: :string
|
35
|
+
}
|
36
|
+
},
|
37
|
+
application: {},
|
38
|
+
database: {}
|
39
|
+
},
|
40
|
+
app: {
|
41
|
+
name: :string,
|
42
|
+
shortname: :string,
|
43
|
+
type: :string,
|
44
|
+
app_source: {
|
45
|
+
type: :string,
|
46
|
+
url: :string,
|
47
|
+
ssh_key: :optional
|
48
|
+
},
|
49
|
+
domains: :array,
|
50
|
+
attributes: {
|
51
|
+
rails_env: :string
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
self.default = {
|
57
|
+
stack: {
|
58
|
+
name: 'Ridoku-Rails',
|
59
|
+
region: 'us-west-1',
|
60
|
+
default_os: 'Ubuntu 12.04 LTS',
|
61
|
+
hostname_theme: 'Legendary_creatures_from_Japan',
|
62
|
+
default_availability_zone: 'us-west-1a',
|
63
|
+
custom_json: '',
|
64
|
+
configuration_manager: {
|
65
|
+
name: 'Chef',
|
66
|
+
version: '11.4'
|
67
|
+
},
|
68
|
+
use_custom_cookbooks:true,
|
69
|
+
custom_cookbooks_source: {
|
70
|
+
type: 'git',
|
71
|
+
url: 'git@github.com:zv1n/ridoku-cookbooks.git',
|
72
|
+
revision: 'stable'
|
73
|
+
},
|
74
|
+
default_root_device_type: 'instance-store'
|
75
|
+
},
|
76
|
+
|
77
|
+
layer: [
|
78
|
+
loadbalance: {
|
79
|
+
standard: true,
|
80
|
+
updates: true,
|
81
|
+
type:'lb',
|
82
|
+
attributes: {
|
83
|
+
enable_haproxy_stats: 'true',
|
84
|
+
haproxy_health_check_method: 'OPTIONS',
|
85
|
+
haproxy_health_check_url: '/',
|
86
|
+
haproxy_stats_url: '/haproxy?stats',
|
87
|
+
},
|
88
|
+
auto_assign_elastic_ips: true,
|
89
|
+
auto_assign_public_ips: true
|
90
|
+
},
|
91
|
+
application: {
|
92
|
+
standard: true,
|
93
|
+
updates: true,
|
94
|
+
type:'rails-app',
|
95
|
+
attributes: {
|
96
|
+
bundler_version: '1.3.5',
|
97
|
+
manage_bundler: 'true',
|
98
|
+
rails_stack: 'nginx_unicorn',
|
99
|
+
ruby_version:'1.9.3',
|
100
|
+
rubygems_version:'2.1.5'
|
101
|
+
},
|
102
|
+
packages: [
|
103
|
+
'imagemagick',
|
104
|
+
'libmagickwand-dev',
|
105
|
+
'nodejs',
|
106
|
+
'postgresql-common',
|
107
|
+
'libpgsql-ruby'
|
108
|
+
],
|
109
|
+
auto_assign_elastic_ips: false,
|
110
|
+
auto_assign_public_ips: true,
|
111
|
+
custom_recipes:{
|
112
|
+
configure: ['postgresql::ruby']
|
113
|
+
}
|
114
|
+
},
|
115
|
+
database: {
|
116
|
+
type: 'custom',
|
117
|
+
name: 'Ridoku-Postgres',
|
118
|
+
shortname: 'ridoku-postgres',
|
119
|
+
attributes: {
|
120
|
+
},
|
121
|
+
auto_assign_elastic_ips: true,
|
122
|
+
auto_assign_public_ips: true,
|
123
|
+
custom_security_group_ids: ['Ridoku-PostgreSQL-Server'],
|
124
|
+
custom_recipes:{
|
125
|
+
setup: ['postgresql::ec2_server'],
|
126
|
+
configure: [],
|
127
|
+
deploy: [],
|
128
|
+
undeploy: [],
|
129
|
+
shutdown: []
|
130
|
+
},
|
131
|
+
instance: {
|
132
|
+
root_device_type: 'ebs-backed'
|
133
|
+
}
|
134
|
+
}
|
135
|
+
],
|
136
|
+
|
137
|
+
app: {
|
138
|
+
app_source: {
|
139
|
+
type: 'git',
|
140
|
+
revision: 'master'
|
141
|
+
},
|
142
|
+
enable_ssl: false,
|
143
|
+
attributes:{
|
144
|
+
auto_bundle_on_deploy: true,
|
145
|
+
document_root: 'public'
|
146
|
+
},
|
147
|
+
},
|
148
|
+
|
149
|
+
instance: {
|
150
|
+
instance_type: 'm1.small',
|
151
|
+
os: 'Ubuntu 12.04 LTS',
|
152
|
+
availability_zone: 'us-west-1a',
|
153
|
+
architecture: 'x86_64',
|
154
|
+
root_device_type: 'instance-store',
|
155
|
+
install_updates_on_boot: true
|
156
|
+
}
|
157
|
+
}
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/lib/ridoku/run.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
#
|
2
|
+
# Command: run
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'ridoku/base'
|
6
|
+
|
7
|
+
module Ridoku
|
8
|
+
register :run
|
9
|
+
|
10
|
+
class Run < Base
|
11
|
+
attr_accessor :environment
|
12
|
+
|
13
|
+
def run
|
14
|
+
command = Base.config[:command]
|
15
|
+
sub_command = (command.length > 0 && command[1]) || nil
|
16
|
+
|
17
|
+
case sub_command
|
18
|
+
when 'command', nil
|
19
|
+
run_command
|
20
|
+
when 'shell'
|
21
|
+
shell
|
22
|
+
else
|
23
|
+
print_run_help
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def create_ssh_path(instance = nil)
|
31
|
+
Base.fetch_instance
|
32
|
+
Base.fetch_account
|
33
|
+
|
34
|
+
instance ||= Base.select_instances(Base.config[:instances]).first
|
35
|
+
|
36
|
+
unless instance
|
37
|
+
$stderr.puts 'Unable to find a valid instance.'
|
38
|
+
print_run_help
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
|
42
|
+
username = Base.account[:user][:user_name].gsub(/[.]/, '')
|
43
|
+
"#{username}@#{instance[:elastic_ip] || instance[:public_ip]}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def command(command = nil, relative_command = true)
|
47
|
+
Base.fetch_app
|
48
|
+
Base.fetch_permissions
|
49
|
+
|
50
|
+
Base.fetch_stack
|
51
|
+
|
52
|
+
# stupid fucking escaping bullshit
|
53
|
+
# So, ruby escapes, so does bash, so does ssh
|
54
|
+
# (all interpreter layers)
|
55
|
+
# Sooo, we have to have an OMFG ridiculous number of backslashes...
|
56
|
+
# to escape one mother fucking value.
|
57
|
+
|
58
|
+
# TODO: The entire 'run' system is fucked. Rethink it.
|
59
|
+
command.gsub!(/\$/, '\\'*14 + '$') if command
|
60
|
+
|
61
|
+
environment =
|
62
|
+
Base.custom_json['deploy'][Base.app[:shortname]]['app_env']
|
63
|
+
|
64
|
+
fail Ridoku::NoSshAccess.new unless
|
65
|
+
Base.permissions[:permissions].first[:allow_ssh]
|
66
|
+
|
67
|
+
if Base.permissions[:permissions].first[:allow_sudo]
|
68
|
+
prefix = "sudo su #{Base.config[:shell_user] || 'root'} -c "
|
69
|
+
else
|
70
|
+
prefix = ''
|
71
|
+
end
|
72
|
+
|
73
|
+
environ = environment.map do |key, val|
|
74
|
+
"#{key}='#{val}'"
|
75
|
+
end.join(' ')
|
76
|
+
|
77
|
+
dir = "/srv/www/#{Base.app[:shortname]}/current"
|
78
|
+
chdir = "cd #{dir}"
|
79
|
+
path = "PATH=/usr/local/bin:#{dir}/script/:${PATH}"
|
80
|
+
network_path = create_ssh_path
|
81
|
+
|
82
|
+
relative = relative_command ? '/usr/bin/env' : ''
|
83
|
+
|
84
|
+
bash_command = (command && "-c \\\\\\\"#{chdir} && #{relative} #{command}\\\\\\\"") || ''
|
85
|
+
|
86
|
+
ssh_command = [
|
87
|
+
"-t #{network_path}",
|
88
|
+
%Q("#{prefix} \\"#{environ} #{path} bash #{bash_command}\\"")
|
89
|
+
]
|
90
|
+
|
91
|
+
ssh_command.unshift("-i #{Base.config[:ssh_key]}") if
|
92
|
+
Base.config[:ssh_key]
|
93
|
+
|
94
|
+
ssh_command.unshift("/usr/bin/env ssh").join(' ')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def shell
|
99
|
+
command = Ridoku::Run.command
|
100
|
+
|
101
|
+
Base.if_debug? do
|
102
|
+
$stdout.puts 'Running shell with command:'
|
103
|
+
$stdout.puts command
|
104
|
+
end
|
105
|
+
|
106
|
+
exec command
|
107
|
+
end
|
108
|
+
|
109
|
+
def run_command
|
110
|
+
command = Ridoku::Run.command(ARGV.join(' '))
|
111
|
+
|
112
|
+
Base.if_debug? do
|
113
|
+
$stdout.puts 'Running command:'
|
114
|
+
$stdout.puts command
|
115
|
+
end
|
116
|
+
|
117
|
+
exec command
|
118
|
+
end
|
119
|
+
|
120
|
+
def print_run_help
|
121
|
+
$stderr.puts <<-EOF
|
122
|
+
Command: run
|
123
|
+
|
124
|
+
Run the specified command on an instance:
|
125
|
+
run[:command] run a command (over ssh) in the release directory
|
126
|
+
run:shell ssh to the specified instance
|
127
|
+
--instance specify the instance (max: 1)
|
128
|
+
--user ssh as user (default: root; optionally: <AWS Username>,
|
129
|
+
or deploy)
|
130
|
+
|
131
|
+
examples:
|
132
|
+
$ run:shell
|
133
|
+
mukujara$
|
134
|
+
EOF
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|