prun-ops 0.0.2
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 +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +44 -0
- data/Rakefile +2 -0
- data/bin/ops +3 -0
- data/lib/prun-ops.rb +5 -0
- data/lib/prun-ops/base.rb +17 -0
- data/lib/prun-ops/cap/all.rb +45 -0
- data/lib/prun-ops/cap/backup.rb +13 -0
- data/lib/prun-ops/cap/diagnosis.rb +38 -0
- data/lib/prun-ops/cap/pull.rb +41 -0
- data/lib/prun-ops/commands/create_domain.rb +16 -0
- data/lib/prun-ops/commands/create_host.rb +17 -0
- data/lib/prun-ops/commands/delete_domain.rb +14 -0
- data/lib/prun-ops/commands/delete_host.rb +16 -0
- data/lib/prun-ops/commands/exec_host.rb +16 -0
- data/lib/prun-ops/commands/list.rb +29 -0
- data/lib/prun-ops/commands/provision_host.rb +11 -0
- data/lib/prun-ops/commands/ship_host.rb +24 -0
- data/lib/prun-ops/commands/unship_host.rb +16 -0
- data/lib/prun-ops/digitalocean.rb +33 -0
- data/lib/prun-ops/docker.rb +16 -0
- data/lib/prun-ops/ops.rb +23 -0
- data/lib/prun-ops/railitie.rb +12 -0
- data/lib/prun-ops/version.rb +3 -0
- data/lib/tasks/backup.rake +74 -0
- data/lib/tasks/db.rake +38 -0
- data/lib/tasks/http.rake +7 -0
- data/lib/tasks/version.rake +36 -0
- data/prun-ops.gemspec +29 -0
- metadata +161 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7ce19c1a37cd9280f418fdc1142b223cf3aece75
|
4
|
+
data.tar.gz: 55b63a94ba66b0a8da449a0265c02453152c9b90
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cabaa6e99e1483bd7225e2577c1fb680bfcd1965c4cf76b4fc8ff6e301661bd99bf0187a28f2d93ecdda7eba8b3d393fcf4704f0a06a49c0fb1e1ba6a194eb97
|
7
|
+
data.tar.gz: f46107d1b5313bafeb3ed1bc2929b673f298978f49c8c30dcd43266907b553be5a33013d1e4bc7862e8b8091ed783af3d10cee6d052f7b389546d6a499e2b848
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Juan Lebrijo
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# PrunOps
|
2
|
+
|
3
|
+
Covers all Operations in a Ruby on Rails Application server:
|
4
|
+
|
5
|
+
1. PROVISION: Create hosts and ship them with Docker containers.
|
6
|
+
1. CONFIGURATION: Build Chef cookbooks and configure/re-configure your servers. Based on [PRUN-CFG cookbook](https://1upermarket.getchef.com/cookbooks/prun-cfg).
|
7
|
+
1. DEPLOYMENT: Capistrano tasks to depoly your rails Apps.
|
8
|
+
1. DIAGNISIS: Capistrano diagnosis tools to guet your Apps status on real time.
|
9
|
+
1. RELEASE: Rake tasks to manage and tag version number in your Apps (X.Y.Z).
|
10
|
+
1. BACKUP: Backup policy for database and files in your Apps, using git as storage.
|
11
|
+
|
12
|
+
Based on [PRUN docker image](https://registry.hub.docker.com/u/jlebrijo/prun/).
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'prun-ops'
|
20
|
+
```
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
$ gem install prun-ops
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
TODO: Write usage instructions here
|
33
|
+
|
34
|
+
## Contributing
|
35
|
+
|
36
|
+
1. Fork it ( https://github.com/[my-github-username]/prun-ops/fork )
|
37
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
38
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
39
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
40
|
+
5. Create a new Pull Request
|
41
|
+
|
42
|
+
## License
|
43
|
+
|
44
|
+
[MIT License](http://opensource.org/licenses/MIT). Copyright 2009-2014 at [Lebrijo.com](http://lebrijo.com)
|
data/Rakefile
ADDED
data/bin/ops
ADDED
data/lib/prun-ops.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Ops
|
2
|
+
DIR = "ops"
|
3
|
+
HOSTS_DIR = "#{DIR}/hosts"
|
4
|
+
CONTAINERS_DIR = "#{DIR}/containers"
|
5
|
+
PROVIDERS_DIR = "#{DIR}/providers"
|
6
|
+
|
7
|
+
|
8
|
+
def self.get_user_for(host_name)
|
9
|
+
host_file = "#{HOSTS_DIR}/#{host_name}.yml"
|
10
|
+
begin
|
11
|
+
params = YAML.load_file host_file
|
12
|
+
params["user"]
|
13
|
+
rescue
|
14
|
+
raise "Please, create '#{host_file}' configuring your host"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "prun-ops/cap/diagnosis"
|
2
|
+
require "prun-ops/cap/pull"
|
3
|
+
require "prun-ops/cap/backup"
|
4
|
+
|
5
|
+
set :backup_dirs, []
|
6
|
+
|
7
|
+
namespace :deploy do
|
8
|
+
|
9
|
+
desc 'Restart application'
|
10
|
+
task :restart do
|
11
|
+
on roles(:app), in: :sequence, wait: 5 do
|
12
|
+
execute "service thin restart"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
after :publishing, :restart
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
namespace :db do
|
21
|
+
desc 'First DDBB setup'
|
22
|
+
task :setup do
|
23
|
+
on roles(:all) do
|
24
|
+
within release_path do
|
25
|
+
with rails_env: fetch(:stage) do
|
26
|
+
execute :rake, 'db:schema:load'
|
27
|
+
execute :rake, 'db:seed'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
namespace :git do
|
35
|
+
desc 'Git pull for common code project'
|
36
|
+
task :pull_common do
|
37
|
+
on roles(:app) do
|
38
|
+
within "/var/www/common" do
|
39
|
+
execute :git, :pull, :origin, :master
|
40
|
+
end if test("[ -f /var/www/common ]")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
after "deploy:updating", "git:pull_common"
|
45
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
namespace :backup do
|
2
|
+
desc 'Restore data from git repo, last backup by default'
|
3
|
+
task :restore, :tag do |task, args|
|
4
|
+
on roles(:app) do
|
5
|
+
within release_path do
|
6
|
+
with rails_env: fetch(:stage) do
|
7
|
+
execute :rake, "backup:restore #{args[:tag]}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
desc 'SSH connection with server'
|
2
|
+
task :ssh do
|
3
|
+
on roles(:app) do |host|
|
4
|
+
run_locally do
|
5
|
+
run_in host, ""
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'Opens a remote Rails console'
|
11
|
+
task :c do
|
12
|
+
on roles(:app) do |host|
|
13
|
+
run_locally do
|
14
|
+
run_in host, "cd #{current_path} && RAILS_ENV=#{fetch(:stage)} bundle exec rails c"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'Tails the environment log or the log passed as argument: cap log[thin.3000.log]'
|
20
|
+
task :log, :file do |task, args|
|
21
|
+
on roles(:app) do
|
22
|
+
file = args[:file]? args[:file] : "#{fetch(:stage)}.log"
|
23
|
+
execute "tail -f #{shared_path}/log/#{file}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Runs a command in server: cap production x['free -m']"
|
28
|
+
task :x, :command do |task, args|
|
29
|
+
on roles(:app) do |host|
|
30
|
+
run_locally do
|
31
|
+
run_in host, args[:command]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def run_in(host, cmd)
|
37
|
+
exec "ssh #{host.user}@#{host.hostname} -p #{host.port} -tt '#{cmd}'"
|
38
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
namespace :pull do
|
2
|
+
desc 'Pull data (db/files) from remote (i.e: production) application.'
|
3
|
+
task :data do
|
4
|
+
invoke "files:pull"
|
5
|
+
invoke "db:pull"
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'Pull db'
|
9
|
+
task :db do
|
10
|
+
on roles(:app) do |host|
|
11
|
+
debug ": Pulling database from #{fetch(:stage)} ..."
|
12
|
+
within "#{current_path}/tmp" do
|
13
|
+
with rails_env: :production do
|
14
|
+
rake "db:backup"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
run_locally do
|
18
|
+
execute "scp -P #{host.port} #{host.user}@#{host.hostname}:#{current_path}/tmp/db.sql tmp/"
|
19
|
+
rake "db:restore tmp/db.sql"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Pull files uploaded'
|
26
|
+
task :files do
|
27
|
+
on roles(:app) do |host|
|
28
|
+
run_locally do
|
29
|
+
debug ": Pulling Files from #{fetch(:stage)} ..."
|
30
|
+
if fetch(:backup_dirs).any?
|
31
|
+
fetch(:backup_dirs).each do |dir|
|
32
|
+
execute "scp -r -P #{host.port} #{host.user}@#{host.hostname}:#{current_path}/#{dir} #{dir}"
|
33
|
+
end
|
34
|
+
else
|
35
|
+
error ": Set key :backup_dirs to know which ones to pull"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
command :'create domain' do |c|
|
2
|
+
c.summary = 'Create a domain in your DigitalOcean account'
|
3
|
+
c.syntax = 'ops create domain [domain name] [ip address]'
|
4
|
+
c.description = "Create the domain with #{DigitalOcean::CONFIG_FILE} credentials"
|
5
|
+
c.example 'Create the domain example.com in your DigitalOcean console', 'ops create domain example.com'
|
6
|
+
c.action do |args, options|
|
7
|
+
ip = (args[1].nil?)? '1.1.1.1':args[1]
|
8
|
+
domain = DropletKit::Domain.new(ip_address: ip, name: args[0])
|
9
|
+
resp = DigitalOcean::client.domains.create domain
|
10
|
+
if domain == resp
|
11
|
+
say "Domain #{resp.name} succesfully created!"
|
12
|
+
else
|
13
|
+
raise resp
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
command :'create host' do |c|
|
2
|
+
c.summary = 'Create a droplet/host in your DO account'
|
3
|
+
c.syntax = 'ops create host [DNS_name]'
|
4
|
+
c.description = "Creates the host described in the file #{Ops::HOSTS_DIR}/[DNS_name].yml"
|
5
|
+
c.example "Create the host example.com in your DigitalOcean console. This is described in '#{Ops::HOSTS_DIR}/example.com.yml' like:\n # size: 512mb\n # region: ams1\n # image: coreos-stable\n # ssh_keys:\n # - e7:51:47:bc:7f:dc:2f:3c:56:65:28:e1:10:9c:88:57 xx:xx:xx:xx:xx:xx:xx", 'ops create host example.com'
|
6
|
+
c.action do |args, options|
|
7
|
+
droplet = DigitalOcean::build_droplet args[0]
|
8
|
+
cli = DigitalOcean::client
|
9
|
+
resp = cli.droplets.create droplet
|
10
|
+
if resp == droplet
|
11
|
+
ip = cli.find_droplet_by_name(args[0]).networks["v4"].first.ip_address
|
12
|
+
say "Droplet #{args[0]} (IP: #{ip}) succesfully created!"
|
13
|
+
else
|
14
|
+
raise resp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
command :'delete domain' do |c|
|
2
|
+
c.summary = 'Delete a domain in your DigitalOcean account'
|
3
|
+
c.syntax = 'ops delete domain [domain name]'
|
4
|
+
c.description = "Delete the domain with #{DigitalOcean::CONFIG_FILE} credentials"
|
5
|
+
c.example 'Delete the domain example.com in your DigitalOcean console', 'ops delete domain example.com'
|
6
|
+
c.action do |args, options|
|
7
|
+
resp = DigitalOcean::client.domains.delete name: args[0]
|
8
|
+
if resp.is_a?(TrueClass)
|
9
|
+
say "Domain #{args[0]} succesfully deleted!"
|
10
|
+
else
|
11
|
+
raise resp
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
command :'delete host' do |c|
|
2
|
+
c.summary = 'Delete a host in your DigitalOcean account'
|
3
|
+
c.syntax = 'ops delete host [DNS_name]'
|
4
|
+
c.description = "Delete the host, based on DNS_name, which (not need but) should be described in its #{Ops::HOSTS_DIR}/[DNS_name].yml file "
|
5
|
+
c.example 'Delete the host example.com in your DigitalOcean console', 'ops delete host example.com'
|
6
|
+
c.action do |args, options|
|
7
|
+
cli = DigitalOcean::client
|
8
|
+
id = cli.find_droplet_by_name(args[0]).id
|
9
|
+
resp = cli.droplets.delete id: id
|
10
|
+
if resp.is_a?(TrueClass)
|
11
|
+
say "Droplet #{args[0]} succesfully deleted!"
|
12
|
+
else
|
13
|
+
raise resp
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
command :'exec host' do |c|
|
2
|
+
c.summary = 'Execute a command in host'
|
3
|
+
c.description = "Execute a command in host defined by DNS_name"
|
4
|
+
c.syntax = 'ops exec host [host_name] "[command]"'
|
5
|
+
c.example "", "ops exec host example.com 'docker ps -a'"
|
6
|
+
c.action do |args, options|
|
7
|
+
host = args[0]
|
8
|
+
user = Ops::get_user_for(host)
|
9
|
+
|
10
|
+
Net::SSH.start(host, user) do |ssh|
|
11
|
+
Docker::containers_for(host).each do |container_name, config|
|
12
|
+
ssh.exec args[1]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
command :list do |c|
|
2
|
+
c.summary = 'List all droplet creation parameters'
|
3
|
+
c.syntax = 'ops list'
|
4
|
+
c.description = "This shows a list in the format '- [id] => [description]'. Use [id] values to create your host file in #{Ops::DIR}/hosts/[dns_name].yml "
|
5
|
+
c.action do |args, options|
|
6
|
+
cli = DigitalOcean::client
|
7
|
+
say "\nDESCRIPTION: #{c.description}\n"
|
8
|
+
|
9
|
+
say "\nSizes:"
|
10
|
+
cli.sizes.all.each do |i|
|
11
|
+
say " - #{i.slug.ljust(6)} => $#{i.price_monthly}/mo"
|
12
|
+
end
|
13
|
+
|
14
|
+
say "\nRegions:"
|
15
|
+
cli.regions.all.each do |i|
|
16
|
+
say " - #{i.slug.ljust(6)} => #{i.name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
say "\nImages:"
|
20
|
+
cli.images.all.each do |i|
|
21
|
+
say " - #{i.slug.ljust(20)} => #{i.distribution} #{i.name}"
|
22
|
+
end
|
23
|
+
|
24
|
+
say "\nSSH Keys:"
|
25
|
+
cli.ssh_keys.all.each do |i|
|
26
|
+
say " - #{i.fingerprint} => #{i.name}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
command :'provision host' do |c|
|
2
|
+
c.summary = 'Create and ship the host based on config files'
|
3
|
+
c.syntax = 'ops provision host [host_name]'
|
4
|
+
c.description = "Agregate both commands Create and Ship host"
|
5
|
+
c.example "Creates and ships example.com host", 'ops provisiion host example.com'
|
6
|
+
c.action do |args, options|
|
7
|
+
system "#{program :name} create host #{args.join(" ")}"
|
8
|
+
sleep 15
|
9
|
+
system "#{program :name} ship host #{args.join(" ")}"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
command :'ship host' do |c|
|
2
|
+
c.summary = 'Create Docker containers defined in ops/containers/[host_name].yml'
|
3
|
+
c.syntax = 'ops ship host [host_name]'
|
4
|
+
c.description = "Create all docker containers described in #{Ops::CONTAINERS_DIR}/[host_name].yml"
|
5
|
+
c.example "Create a container called 'www' in the host example.com. This is described in '#{Ops::CONTAINERS_DIR}/example.com.yml' like:\n # www:\n # detach: true\n # image: jlebrijo/prun\n # ports:\n # - '2222:22'\n # - '80:80'", 'ops ship host example.com'
|
6
|
+
c.action do |args, options|
|
7
|
+
host = args[0]
|
8
|
+
user = Ops::get_user_for(host)
|
9
|
+
|
10
|
+
Docker::containers_for(host).each do |container_name, config|
|
11
|
+
ports = config["ports"].map{|port| "-p #{port}"}.join(" ")
|
12
|
+
options = []
|
13
|
+
config.reject{|k| Docker::SPECIAL_OPTS.include? k}.each do |option, value|
|
14
|
+
options << "--#{option}=#{value}"
|
15
|
+
end
|
16
|
+
say "Container '#{container_name}' loading on #{host}, please wait ....\n"
|
17
|
+
Net::SSH.start(host, user) do |ssh|
|
18
|
+
ssh.exec "docker run #{options.join(" ")} --name #{container_name} #{ports} #{config["image"]} #{config["command"]}"
|
19
|
+
end
|
20
|
+
sleep 5
|
21
|
+
config["post-conditions"].each { |c| system c }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
command :'unship host' do |c|
|
2
|
+
c.summary = 'Removes all Docker containers defined for the host in '#{Ops::CONTAINERS_DIR}/[host_name].yml'
|
3
|
+
c.syntax = 'ops ship host [host_name]'
|
4
|
+
c.description = "Removes all Docker containers defined for the host in '#{Ops::CONTAINERS_DIR}/[host_name].yml"
|
5
|
+
c.example "", 'ops unship host example.com'
|
6
|
+
c.action do |args, options|
|
7
|
+
host = args[0]
|
8
|
+
user = Ops::get_user_for(host)
|
9
|
+
|
10
|
+
Net::SSH.start(host, user) do |ssh|
|
11
|
+
Docker::containers_for(host).each do |container_name, config|
|
12
|
+
ssh.exec "docker rm -f #{container_name}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'droplet_kit'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module DigitalOcean
|
5
|
+
CONFIG_FILE = "#{Ops::PROVIDERS_DIR}/digitalocean.yml"
|
6
|
+
|
7
|
+
def self.client
|
8
|
+
begin
|
9
|
+
config = YAML.load_file CONFIG_FILE
|
10
|
+
rescue
|
11
|
+
raise "Please, create '#{CONFIG_FILE}' file with token value"
|
12
|
+
end
|
13
|
+
DropletKit::Client.new(access_token: config["token"])
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.build_droplet(host_name)
|
17
|
+
begin
|
18
|
+
params = YAML.load_file "#{Ops::DIR}/hosts/#{host_name}.yml"
|
19
|
+
params["name"]= host_name
|
20
|
+
rescue
|
21
|
+
raise "Please, create '#{CONFIG_FILE}' file with token value"
|
22
|
+
end
|
23
|
+
DropletKit::Droplet.new params
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module DropletKit
|
28
|
+
class Client
|
29
|
+
def find_droplet_by_name(host_name)
|
30
|
+
self.droplets.all.find{|d| d.name == host_name}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'droplet_kit'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Docker
|
5
|
+
SPECIAL_OPTS = ["image", "ports", "command", "post-conditions"]
|
6
|
+
|
7
|
+
def self.containers_for(host_name)
|
8
|
+
config_file = "#{Ops::CONTAINERS_DIR}/#{host_name}.yml"
|
9
|
+
begin
|
10
|
+
config = YAML.load_file config_file
|
11
|
+
rescue
|
12
|
+
raise "Please, create '#{config_file}' file with all containers configured"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/lib/prun-ops/ops.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'commander/import'
|
3
|
+
require 'net/ssh'
|
4
|
+
require 'prun-ops/base'
|
5
|
+
require 'prun-ops/digitalocean'
|
6
|
+
require 'prun-ops/docker'
|
7
|
+
require 'prun-ops/version'
|
8
|
+
|
9
|
+
program :name, 'ops'
|
10
|
+
program :version, PrunOps::VERSION
|
11
|
+
program :description, 'Helps to manage Provision/Configuration/Deployment processes based on DigitalOcean, Docker, Chef and Capistrano'
|
12
|
+
program :help_formatter, :compact
|
13
|
+
|
14
|
+
require 'prun-ops/commands/list'
|
15
|
+
require 'prun-ops/commands/create_host'
|
16
|
+
require 'prun-ops/commands/delete_host'
|
17
|
+
require 'prun-ops/commands/create_domain'
|
18
|
+
require 'prun-ops/commands/delete_domain'
|
19
|
+
require 'prun-ops/commands/ship_host'
|
20
|
+
require 'prun-ops/commands/unship_host'
|
21
|
+
require 'prun-ops/commands/exec_host'
|
22
|
+
require 'prun-ops/commands/provision_host'
|
23
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
namespace :backup do
|
2
|
+
desc 'Restore and database and :backup_dirs from the git :backup_repo, with the TAG given'
|
3
|
+
task restore: :get_config do
|
4
|
+
pull_repo(tag)
|
5
|
+
sh "rake db:restore #{@backup_path}/db.sql"
|
6
|
+
@asset_folders.each do |folder|
|
7
|
+
dest_folder = "#{Rails.root}/#{folder}"
|
8
|
+
sh "mkdir -p #{dest_folder}" unless File.directory?(dest_folder)
|
9
|
+
sh "cp -r #{@backup_path}/#{folder}/* #{dest_folder}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'Commits and tag the database dump and :backup_dirs into a git :backup_repo'
|
15
|
+
task backup: ["db:backup", :get_config] do
|
16
|
+
pull_repo
|
17
|
+
|
18
|
+
# Gather data
|
19
|
+
sh "mv #{@dump_file} #{@backup_path}"
|
20
|
+
|
21
|
+
@asset_folders.each do |folder|
|
22
|
+
dest_folder = "#{@backup_path}/#{folder}"
|
23
|
+
sh "mkdir -p #{dest_folder}" unless File.directory?(dest_folder)
|
24
|
+
sh "cp -Lr #{Rails.root}/#{folder}/* #{dest_folder}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Pushing data
|
28
|
+
comment = "#{@app_name} backup at #{Time.now.strftime "%F %R"}"
|
29
|
+
sh "git add --all && git commit -m '#{comment}'" do |ok, res|
|
30
|
+
if ! ok
|
31
|
+
puts "Nothing change since last backup"
|
32
|
+
else
|
33
|
+
sh "git push origin master"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Tagging
|
38
|
+
tagname = if tag.blank?
|
39
|
+
"#{@app_name}-#{Date.today.strftime "%Y%m%d" }"
|
40
|
+
else
|
41
|
+
tag
|
42
|
+
end
|
43
|
+
sh "git tag -a #{tagname} -m '#{comment}' -f"
|
44
|
+
sh "git push origin #{tagname}"
|
45
|
+
end
|
46
|
+
|
47
|
+
task :get_config do
|
48
|
+
@environment = Rails.env
|
49
|
+
|
50
|
+
@app_name = Rails.application.class.parent_name.parameterize
|
51
|
+
tmp_dir = "#{Rails.root}/tmp"
|
52
|
+
@repo_path = "#{tmp_dir}/backup"
|
53
|
+
@backup_path = "#{@repo_path}/#{@app_name}"
|
54
|
+
@dump_file = "#{tmp_dir}/db.sql"
|
55
|
+
@git_repo = Rails.configuration.backup_repo
|
56
|
+
@asset_folders = Rails.configuration.backup_dirs
|
57
|
+
end
|
58
|
+
|
59
|
+
def tag
|
60
|
+
name = ARGV[1]
|
61
|
+
task name.to_sym do ; end unless name.nil?
|
62
|
+
return name
|
63
|
+
end
|
64
|
+
|
65
|
+
def pull_repo(tag="")
|
66
|
+
if File.directory?(@repo_path)
|
67
|
+
cd "#{@repo_path}"
|
68
|
+
sh "git pull origin master"
|
69
|
+
else
|
70
|
+
sh "git clone #{@git_repo} #{@repo_path}"
|
71
|
+
cd "#{@repo_path}"
|
72
|
+
end
|
73
|
+
sh "git checkout tags/#{tag}" unless tag.blank?
|
74
|
+
end
|
data/lib/tasks/db.rake
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
namespace :db do
|
2
|
+
desc "Reset DataBase for environment and test"
|
3
|
+
task :reset do
|
4
|
+
Rake::Task['db:drop'].invoke
|
5
|
+
Rake::Task['db:create'].invoke
|
6
|
+
Rake::Task['db:migrate'].invoke
|
7
|
+
Rake::Task['db:seed'].invoke
|
8
|
+
sh "rake db:test:prepare"
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Backup the database tp tmp/db.sql file"
|
12
|
+
task backup: :get_db_config do
|
13
|
+
sh "export PGPASSWORD=#{@password} && pg_dump #{@database} -U #{@username} -f #{@default_filename}"
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Restore the database from tmp/db.sql file if no one is passed"
|
17
|
+
task restore: [:drop, :create, :get_db_config] do
|
18
|
+
sh "export PGPASSWORD=#{@password} && psql -d #{@database} -U #{@username} < #{filename}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
task :get_db_config do
|
23
|
+
config = Rails.configuration.database_configuration
|
24
|
+
@database = config[Rails.env]["database"]
|
25
|
+
@username = config[Rails.env]["username"]
|
26
|
+
@password = config[Rails.env]["password"]
|
27
|
+
|
28
|
+
@default_filename = "tmp/db.sql"
|
29
|
+
end
|
30
|
+
|
31
|
+
def filename
|
32
|
+
name = ARGV[1]
|
33
|
+
task name.to_sym do ; end unless name.nil?
|
34
|
+
return name ? name : @default_filename
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
|
data/lib/tasks/http.rake
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
desc "Version control"
|
2
|
+
namespace :version do
|
3
|
+
desc "Release a version: rake version:release version_tag"
|
4
|
+
task :release, :number do |t, args|
|
5
|
+
version_tag = get_version_tag
|
6
|
+
# Merge dev/master and push
|
7
|
+
sh "git show-branch dev" do |ok, res|
|
8
|
+
if ok
|
9
|
+
sh "git checkout master && git merge dev && git push && git checkout dev"
|
10
|
+
else
|
11
|
+
sh "git push"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Tagging
|
16
|
+
sh "git tag -a #{version_tag} -m 'Version #{version_tag} - #{Time.now.to_date}'"
|
17
|
+
sh "git push origin --tags"
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Delete a version: rake version:remove version_tag "
|
21
|
+
task :remove, :number do |t, args|
|
22
|
+
version_tag = get_version_tag
|
23
|
+
sh "git tag -d #{version_tag}"
|
24
|
+
sh "git push origin :refs/tags/#{version_tag}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_version_tag
|
28
|
+
if ARGV[1].nil?
|
29
|
+
puts "We need a version tag: $ rake version:release version_tag"
|
30
|
+
raise
|
31
|
+
else
|
32
|
+
ARGV[1]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/prun-ops.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'prun-ops/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "prun-ops"
|
8
|
+
spec.version = PrunOps::VERSION
|
9
|
+
spec.authors = ["Juan Lebrijo"]
|
10
|
+
spec.email = ["juan@lebrijo.com"]
|
11
|
+
spec.summary = %q{Encapsulates Operations commands needed for a Rails Application.}
|
12
|
+
spec.description = %q{Encapsulates Operations commands for Rails Applications: Provision, Configure, Deploy, Diagnose, Version Releasing and Backup.}
|
13
|
+
spec.homepage = "http://www.lebrijo.com"
|
14
|
+
spec.license = "GPLv3"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
spec.executables = ['ops']
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
|
25
|
+
spec.add_runtime_dependency "capistrano-rails"
|
26
|
+
spec.add_runtime_dependency "commander"
|
27
|
+
spec.add_runtime_dependency "thin", "1.6.2"
|
28
|
+
spec.add_runtime_dependency "droplet_kit"
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: prun-ops
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Juan Lebrijo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: capistrano-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: commander
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: thin
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.6.2
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.6.2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: droplet_kit
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: 'Encapsulates Operations commands for Rails Applications: Provision,
|
98
|
+
Configure, Deploy, Diagnose, Version Releasing and Backup.'
|
99
|
+
email:
|
100
|
+
- juan@lebrijo.com
|
101
|
+
executables:
|
102
|
+
- ops
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- ".gitignore"
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE.txt
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- bin/ops
|
112
|
+
- lib/prun-ops.rb
|
113
|
+
- lib/prun-ops/base.rb
|
114
|
+
- lib/prun-ops/cap/all.rb
|
115
|
+
- lib/prun-ops/cap/backup.rb
|
116
|
+
- lib/prun-ops/cap/diagnosis.rb
|
117
|
+
- lib/prun-ops/cap/pull.rb
|
118
|
+
- lib/prun-ops/commands/create_domain.rb
|
119
|
+
- lib/prun-ops/commands/create_host.rb
|
120
|
+
- lib/prun-ops/commands/delete_domain.rb
|
121
|
+
- lib/prun-ops/commands/delete_host.rb
|
122
|
+
- lib/prun-ops/commands/exec_host.rb
|
123
|
+
- lib/prun-ops/commands/list.rb
|
124
|
+
- lib/prun-ops/commands/provision_host.rb
|
125
|
+
- lib/prun-ops/commands/ship_host.rb
|
126
|
+
- lib/prun-ops/commands/unship_host.rb
|
127
|
+
- lib/prun-ops/digitalocean.rb
|
128
|
+
- lib/prun-ops/docker.rb
|
129
|
+
- lib/prun-ops/ops.rb
|
130
|
+
- lib/prun-ops/railitie.rb
|
131
|
+
- lib/prun-ops/version.rb
|
132
|
+
- lib/tasks/backup.rake
|
133
|
+
- lib/tasks/db.rake
|
134
|
+
- lib/tasks/http.rake
|
135
|
+
- lib/tasks/version.rake
|
136
|
+
- prun-ops.gemspec
|
137
|
+
homepage: http://www.lebrijo.com
|
138
|
+
licenses:
|
139
|
+
- GPLv3
|
140
|
+
metadata: {}
|
141
|
+
post_install_message:
|
142
|
+
rdoc_options: []
|
143
|
+
require_paths:
|
144
|
+
- lib
|
145
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
requirements: []
|
156
|
+
rubyforge_project:
|
157
|
+
rubygems_version: 2.4.2
|
158
|
+
signing_key:
|
159
|
+
specification_version: 4
|
160
|
+
summary: Encapsulates Operations commands needed for a Rails Application.
|
161
|
+
test_files: []
|