Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit f2fd992392bd9ffe1671589d1b3666a1aeba404a @kenn committed Feb 25, 2012
@@ -0,0 +1,4 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in sunzi.gemspec
+gemspec
@@ -0,0 +1,70 @@
+Sunzi
+=====
+
+```
+"The supreme art of war is to subdue the enemy without fighting." - Sunzi
+```
+
+Sunzi is a server provisioning tool for minimalists. Simplicity is the one and only goal - if Chef or Puppet is driving you nuts, try Sunzi.
+
+Sunzi assumes that Linux distributions have (mostly) sane defaults.
+
+Its design goals are:
+
+* A big-bang overwriting with loads of custom configurations makes it difficult to know **what you are actually doing** - instead, Sunzi let you keep track of as little diff from default as possible.
+* No mysterious Ruby DSL involved. Sunzi recipes are written in a plain shell script. Why? Because, most of the information about server configuration you get on the web is written in a set of shell commands. Why should you translate it into a proprietary DSL, rather than just copy-paste?
+* No configuration server. No dependency. You don't even need a Ruby runtime on the remote server.
+
+Quickstart
+----------
+
+Install:
+
+ $ gem install sunzi
+
+Go to your project directory, then:
+
+ $ sunzi create
+
+It generates a `sunzi` folder, subdirectories and some templates for you. Inside `sunzi`, there's `here` folder, which will be kept in your local machine, that contains some scripts and definition files. Also there's `there` folder, which will be transferred to the remote server, that contains recipes and dynamic variables compiled from the definition files in the `here` folder.
+
+Go into the `here` directory, then run the `deploy.sh`:
+
+ $ cd sunzi/here
+ $ bash deploy.sh root@example.com
+
+Now, what it actually does is:
+
+1. SSH to `example.com` and login as `root`
+1. Transfer the content of the `there` directory to the remote server and extract in `$HOME/sunzi`
+1. Run `install.sh` in the remote server
+
+As you can see, what you need to do is edit `install.sh` and add some shell commands. That's it.
+
+Tutorial
+--------
+
+Here's the directory structure that `sunzi create` automatically generates:
+
+```
+sunzi/
+ here/ ---- kept in your local machine
+ attributes.yml ---- add custom variables here
+ compile.rb ---- compile the content of attributes.yml to there/attributes/*
+ deploy.sh ---- invoke this script
+ there/ ---- transferred to the remote server
+ attributes/ ---- compiled from attributes.yml at deploy
+ env
+ ssh_key
+ recipes/ ---- put commonly used scripts here, referred from install.sh
+ ssh_key.sh
+ install.sh ---- main scripts that gets run on the remote server
+```
+
+Vagrant
+-------
+
+If you're using Sunzi with [Vagrant](http://vagrantup.com/), make sure you allowed SSH access for root, then:
+
+ $ vagrant up
+ $ bash deploy.sh root@localhost -p 2222
@@ -0,0 +1 @@
+require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require File.expand_path('../../lib/sunzi',__FILE__)
+Sunzi::Cli.start
@@ -0,0 +1,8 @@
+LIB_PATH = File.join(File.dirname(__FILE__), 'sunzi')
+
+module Sunzi
+ autoload :Base, File.join(LIB_PATH, 'base')
+ autoload :Cli, File.join(LIB_PATH, 'cli')
+ autoload :Dependency, File.join(LIB_PATH, 'dependency')
+ autoload :Version, File.join(LIB_PATH, 'version')
+end
@@ -0,0 +1,9 @@
+require 'yaml'
+
+module Sunzi
+ class Base
+ def initialize(project)
+ # Do something
+ end
+ end
+end
@@ -0,0 +1,30 @@
+require 'thor'
+
+module Sunzi
+ CONFIG_DIR = File.join(ENV['HOME'],'.config','sunzi')
+
+ class Cli < Thor
+ include Thor::Actions
+
+ class << self
+ def source_root
+ File.expand_path('../../',__FILE__)
+ end
+ end
+
+ map "c" => :create
+
+ desc "create [PROJECT]", "Create sunzi project (Shortcut: c)"
+ def create(project = 'sunzi')
+ empty_directory project
+ empty_directory "#{project}/here"
+ empty_directory "#{project}/there"
+ empty_directory "#{project}/there/recipes"
+ template "templates/here/attributes.yml", "#{project}/here/attributes.yml"
+ template "templates/here/compile.rb", "#{project}/here/compile.rb"
+ template "templates/here/deploy.sh", "#{project}/here/deploy.sh"
+ template "templates/there/install.sh", "#{project}/there/install.sh"
+ template "templates/there/recipes/ssh_key.sh", "#{project}/there/recipes/ssh_key.sh"
+ end
+ end
+end
@@ -0,0 +1,3 @@
+module Sunzi
+ VERSION = "0.0.1"
+end
@@ -0,0 +1,3 @@
+--- # Dynamic variables here will be compiled to individual files in there/attributes.
+env: production
+ssh_key: id_rsa.pub
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+
+require 'yaml'
+hash = YAML.load(File.read('attributes.yml'))
+
+require 'fileutils'
+FileUtils.mkdir_p('../there/attributes')
+
+hash.each do |key, value|
+ File.open("../there/attributes/#{key}", 'w'){|file| file.write(value) }
+end
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Usage: bash deploy.sh [host] [-p 2222]
+
+if [ -z "$1" ]; then
+ echo "Usage: bash deploy.sh user@example.com"
+ exit 1
+fi
+
+# Compile attributes
+ruby compile.rb
+
+# The host key might change when we instantiate a new VM, so
+# we remove (-R) the old host key from known_hosts
+host="$1"
+ssh-keygen -R "${host#*@}" 2> /dev/null
+
+# Connect to the remote server and deploy
+cd ../there
+tar cz . | ssh -o 'StrictHostKeyChecking no' "$host" "$2" "$3" '
+rm -rf ~/sunzi &&
+mkdir ~/sunzi &&
+cd ~/sunzi &&
+tar xz &&
+bash install.sh'
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# SSH key
+source recipes/ssh_key.sh $(cat attributes/ssh_key)
+
+# Update apt catalog
+aptitude update
+aptitude -y safe-upgrade
@@ -0,0 +1,17 @@
+# SSH key
+# $1: SSH key filename
+
+if [ -f ~/.ssh/authorized_keys ]; then
+ echo 'authorized_keys already created'
+else
+ if [ -f "$1" ]; then
+ mkdir -p ~/.ssh
+ cat $1 > ~/.ssh/authorized_keys
+ rm $1
+ chmod 700 ~/.ssh
+ chmod 600 ~/.ssh/authorized_keys
+ else
+ echo 'The public key file ($1) not found! Copy it from $HOME/.ssh to the "there" directory.'
+ echo 'If the file name found in .ssh is different from $1, edit here/attributes.yml as appropriate.'
+ fi
+fi
@@ -0,0 +1,23 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "sunzi/version"
+
+Gem::Specification.new do |s|
+ s.name = "sunzi"
+ s.version = Sunzi::VERSION
+ s.authors = ["Kenn Ejima"]
+ s.email = ["kenn.ejima@gmail.com"]
+ s.homepage = "http://github.com/kenn/sunzi"
+ s.summary = %q{Server provisioning tool for minimalists}
+ s.description = %q{The supreme art of war is to subdue the enemy without fighting.}
+
+ s.rubyforge_project = "sunzi"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+
+ # s.add_development_dependency "rspec"
+ s.add_runtime_dependency "thor"
+end

0 comments on commit f2fd992

Please sign in to comment.