Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
DAddYE committed Aug 9, 2011
0 parents commit 31c266e
Show file tree
Hide file tree
Showing 15 changed files with 960 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
@@ -0,0 +1,17 @@
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
4 changes: 4 additions & 0 deletions Gemfile
@@ -0,0 +1,4 @@
source 'http://rubygems.org'

# Specify your gem's dependencies in do.gemspec
gemspec
289 changes: 289 additions & 0 deletions README.md
@@ -0,0 +1,289 @@
# DO .. it! - Framework Toolkit for Sysadmin

DO is a thin framework useful to manage remote servers through ssh.

There are many other alternative, once of them is [capistrano](https://github.com/capistrano/capistrano)

So why another one? Basically I need:

* easy creation of my recipes
* see perfectly what's happening on my remote servers
* highly focus on smart actions, upload, download, sudo, replace.
* manage more than one server each
* use same behaviour for manage local tasks

## Files

There are some way to generate **DO** tasks, you can:

* Create a file called `Do` in your project directory
* Create a file called `Dofile` in your project directory
* Create `*.rake` files in `~/.do` directory, aka **home dir**
* Create a file called `dorc` in `~/.do` directory

You can change your **do home directory** with:

```
DO_PATH='/my/new/.do/path'
ENV['DO_PATH']='/my/new/.do/path'
export DO_PATH='/my/new/.do/path'
```

## Features

* Easily server logging
* SSH connections
* SFTP connections (upload and download)
* run cmd (we handle also with input)
* shortcuts (exist?, read, replace, append etc...)

Code is much better:

```rb
server = DO::Server.new('srv1', 'srv1.domain.local', 'root', :key => %w[srv1.pem]

server.run 'uname'
# root@srv1 ~ # uname
# Linux

server.run 'uname', '-a'
# root@srv1 ~ # uname -a
# Linux srv1.lipsiasoft.net 2.6.18-194.32.1.el5 x86_64 x86_64 x86_64 GNU/Linux

server.run 'mysqladmin -u root -p password 'oldone', 'newpassword'
# root@srv1 ~ # mysqladmin -u root -p password 'oldone'
# Enter password: oldone
# mysqladmin: connect to server at 'localhost' failed
# error: 'Access denied for user 'root'@'localhost' (using password: YES)'
server.exist?('~/.ssh')
# root@srv1 ~ # test -e ~/.ssh && echo True
# => true
server.read('/etc/redhat-release')
# root@srv1 ~ # cat /etc/redhat-release
# => "CentOS release 5.5 (Final)"
server.upload '/tmp/file', '/tmp/foo'
# root@srv1 ~ # upload from '/tmp/file' to '/tmp/foo'
server.download '/tmp/foo', '/tmp/file2'
# root@srv1 ~ # download from '/tmp/foo' to '/tmp/file2'
server.replace :all, 'new content', '/tmp/file'
# root@srv1 ~ # replace all in '/tmp/foo'
server.read('/tmp/foo')
# root@srv1 ~ # cat /tmp/foo
# => "new content"
server.replace /content$/, 'changed content', '/tmp/foo'
# root@srv1 ~ # replace /content$/ in '/tmp/foo'
server.read('/tmp/foo')
# root@srv1 ~ # cat /tmp/foo
# => "new changed content"
server.append('appended', '/tmp/foo')
# root@srv1 ~ # append to 'bottom' in '/tmp/foo'
server.read('/tmp/foo')
# root@srv1 ~ # cat /tmp/foo
# => "new changed contentappended"
server.append('---', '/tmp/foo', :top)
# root@srv1 ~ # append to 'top' in '/tmp/foo'
server.read('/tmp/foo')
# root@srv1 ~ # cat /tmp/foo
# => "---new changed contentappended"
server.ask "Please choose"
# root@srv1 ~ # Please choose: foo
# => "foo"
server.yes? "Do you want to proceed"
# root@srv1 ~ # Do you want to proceed? (y/n): y
# => 0
server.wait
# Press ENTER to continue...
```
## Scenario and examples
I'm porting my custom recipes to do, you can found my dot files
[here](https://github.com/daddye/.do)

I've server config in `~/.do/dorc`:
```rb
keys = %w(/keys/master.pem /keys/instances.pem /keys/stage.pem)
server :sho0, 'sho0.lipsiasoft.biz', 'root', :keys => keys
server :srv0, 'srv0.lipsiasoft.biz', 'root', :keys => keys
server :srv1, 'srv1.lipsiasoft.biz', 'root', :keys => keys
server :srv2, 'srv2.lipsiasoft.biz', 'root', :keys => keys
plugin "configure-server", "https://raw.github.com/gist/112..."
```
Then I've some recipes in my `~/.do` path where I do common tasks.

```rb
# ~/.do/configure.
namespace :configure
desc "upgrade rubygems and install usefull gems"
task :gems => :ree do
run "gem update --system" if yes?("Do you want to update rubygems?")
run "gem install rake"
run "gem install highline"
run "gem install bundler"
run "ln -s /opt/ruby-enterprise/bin/bundle /usr/bin/bundle" unless exist?("/usr/bin/bundle")
end
desc "create motd for each server"
task :motd do
replace :all, "Hey boss! Welcome to the \e[1m#{name}\e[0m of LipsiaSOFT s.r.l.\n", "/etc/motd"
end
desc "redirect emails to a real account"
task :root_emails do
append "\nroot: servers@lipsiasoft.com", "/etc/aliases"
run "newaliases"
end
desc "mysql basic configuration"
task :mysql => :yum do
run "yum install mysql-server mysql mysql-devel -y"
run "chkconfig --level 2345 mysqld on"
run "service mysqld restart"
pwd = ask "Tell me the password for mysql"
run "mysqladmin -u root -p password '#{pwd}'", :input => "\n"
run "service mysqld restart"
run "ln -fs /var/lib/mysql/mysql.sock /tmp/mysql.sock"
end
...
```

I call those with:

```sh
$ do configure:gems
$ do configure:motd
$ do configure:mysql
```

**NOTE** that like rake tasks you are be able to add prerequisites to
any task, in this case:

```rb
task :mysql => :yum do; ...; end
```

That's are some local tasks:
```rb
namespace :l do
local :setup do
name = File.basename(File.expand_path('.'))
exit unless yes?('Do you want to setup "%s"?' % name)
srv = nil

until servers.map(&:name).include?(srv)
srv = ask("Which server do you want to use (%s)" % servers.map(&:name).join(", ")).to_sym
end

if File.exist?('.git')
exit unless yes?('Project "%s" has already a working repo, do you want remove it?' % name)
sh 'rm -rf .git'
end

sh 'git init'
sh 'git remote add origin git@lipsiasoft.biz:/%s.git' % name
Rake::Task['l:commit'].invoke if yes?("Are you ready to commit it, database, config etc is correct?")
end

local :commit do
sh 'git add .'
sh 'git commit -a'
sh 'git push origin master'
end
end
```

When I need to setup a new project I do:

``` sh
$ do l:setup
$ do l:commit # to make a fast commit and push
```

As you can see define remote and local task is simple like making common
rake tasks, infact this gem handle rake.

## Filtering

Sometimes you want to perform a task only on one or some servers:

```sh
$ do configure:new --only-srv1 --only-srv2
$ do configure:new --except-srv1
```

## Awesome output

What I really need is a great understandable, colored output that clarify
me what's happen on my remote servers.

```
root@sho0 ~ # touch /root/.bashrc
root@sho0 ~ # replace all in '/root/.bashrc'
root@sho0 ~ # replace all in '/etc/motd'
root@sho0 ~ # replace /HOSTNAME=.*/ in '/etc/sysconfig/network'
root@sho0 ~ # chmod +w /etc/sudoers
root@sho0 ~ # replace /^Defaults requiretty/ in '/etc/sudoers'
root@sho0 ~ # chkconfig --level 2345 sendmail on
root@sho0 ~ # chkconfig --level 2345 mysqld on
root@sho0 ~ # service sendmail restart
Shutting down sm-client: [ OK ]
Shutting down sendmail: [ OK ]
Starting sendmail: [ OK ]
Starting sm-client: [ OK ]
root@sho0 ~ # service mysqld restart
Stopping mysqld: [ OK ]
Starting mysqld: [ OK ]
root@sho0 ~ # Tell me the password for mysql: xx
root@sho0 ~ # mysqladmin -u root -p password xx'
Enter password: xx
mysqladmin: connect to server at 'localhost' failed
error: 'Access denied for user 'root'@'localhost' (using password: NO)'
root@sho0 ~ # service mysqld restart
Stopping mysqld: [ OK ]
Starting mysqld: [ OK ]
root@sho0 ~ # ln -fs /var/lib/mysql/mysql.sock /tmp/mysql.sock
```

## Copyright

Copyright (C) 2011 Davide D'Agostino -
[@daddye](http://twitter.com/daddye)

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and
associated documentation files (the “Software”), to deal in the Software
without restriction, including without
limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 changes: 28 additions & 0 deletions Rakefile
@@ -0,0 +1,28 @@
#!/usr/bin/env rake
require 'bundler/setup'
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'

%w(install release).each do |task|
Rake::Task[task].enhance do
sh "rm -rf pkg"
end
end

desc "Bump version on github"
task :bump do
puts "\e[31mNothing to commit (working directory clean)\e[0m" and return unless `git status -s`.chomp!
version = Bundler.load_gemspec(Dir[File.expand_path('../*.gemspec', __FILE__)].first).version
sh "git add .; git commit -a -m \"Bump to version #{version}\""
end

task :release => :bump

desc "Run complete application spec suite"
RSpec::Core::RakeTask.new("spec") do |t|
t.skip_bundler = true
t.pattern = './spec/**/*_spec.rb'
t.rspec_opts = %w(-fs --color --fail-fast)
end

task :default => :spec
30 changes: 30 additions & 0 deletions bin/do
@@ -0,0 +1,30 @@
#!/usr/bin/env ruby
$:.push File.expand_path("../../lib", __FILE__)
require 'rubygems' unless defined?(Gem)
require 'rake/dsl_definition'
require 'rake'
require 'do'

ARGV << "-T" if ARGV.empty?

only = ARGV.map { |a| a =~ /--only-(.*)/ && $1.to_sym }.compact
except = ARGV.map { |a| a =~ /--except-(.*)/ && $1.to_sym }.compact

ARGV.delete_if { |a| a =~ /--(only|except)/ }

puts "\e[32m"
puts "*" * 60
puts "*" + "DO".center(58) + "*"
puts "*" * 60
puts "\e[0m"

Rake.application.init
Rake.application.instance_variable_set(:@name, 'do')
load(File.expand_path('../../lib/do/commands.rb', __FILE__))
DO.recipes.each { |recipe| Rake.application.add_import(recipe) }
Rake.application.load_imports

servers.delete_if { |server| !only.include?(server.name) } unless only.empty?
servers.delete_if { |server| except.include?(server.name) }

Rake.application.top_level
21 changes: 21 additions & 0 deletions do.gemspec
@@ -0,0 +1,21 @@
# -*- encoding: utf-8 -*-
require File.expand_path('../lib/do/version', __FILE__)

Gem::Specification.new do |gem|
gem.authors = ["Davide D'Agostino"]
gem.email = ["d.dagostino@lipsiasoft.com"]
gem.description = %q[DO is a thin framework useful to manage remote servers through ssh.]
gem.summary = %q[DO is a thin framework useful to manage remote servers through ssh.]
gem.homepage = 'https://github.com/daddye/do'

gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
gem.files = `git ls-files`.split("\n")
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
gem.name = "do"
gem.require_paths = ['lib']
gem.version = DO::VERSION
gem.add_dependency "rake", "~>0.9.2"
gem.add_dependency "net-ssh", "~>2.1.4"
gem.add_dependency "net-sftp", "~>2.0.5"
gem.add_development_dependency "rspec"
end

0 comments on commit 31c266e

Please sign in to comment.