sunzi 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -11,8 +11,8 @@ Sunzi assumes that modern Linux distributions have (mostly) sane defaults and gr
11
11
 
12
12
  Its design goals are:
13
13
 
14
- * **It's just shell script.** No clunky Ruby DSL involved. Sunzi recipes are written in a plain shell script. Why? Because, most of the information about server configuration on the web is written in shell commands. Just copy-paste them, why should you translate it into a proprietary, inconvenience DSL? Also, shell script is the greatest common denominator on minimum Linux installs.
15
- * **Focus on diff from default.** No big-bang overwriting. Append or replace the smallest possible piece of data in a config file. Loads of custom configurations makes it difficult to understand what you are really doing.
14
+ * **It's just shell script.** No clunky Ruby DSL involved. Sunzi recipes are written in a plain shell script. Why? Because, most of the information about server configuration on the web is written in shell commands. Just copy-paste them, why should you translate it into a proprietary, inconvenient DSL? Also, shell script is the greatest common denominator on minimum Linux installs.
15
+ * **Focus on diff from default.** No big-bang overwriting. Append or replace the smallest possible piece of data in a config file. Loads of custom configurations make it difficult to understand what you are really doing.
16
16
  * **Always use the root user.** Think twice before blindly assuming you need a regular user - it doesn't add any security benefit for server provisioning, it just adds extra verbosity for nothing. However, it doesn't mean that you shouldn't create regular users with Sunzi - feel free to write your own recipes.
17
17
  * **Minimum dependencies.** No configuration server required. You don't even need a Ruby runtime on the remote server.
18
18
 
@@ -32,7 +32,7 @@ It generates a `sunzi` folder along with subdirectories and templates. Inside `s
32
32
  Go into the `sunzi` directory, then run the `sunzi deploy`:
33
33
 
34
34
  $ cd sunzi
35
- $ sunzi deploy root@example.com
35
+ $ sunzi deploy example.com
36
36
 
37
37
  Now, what it actually does is:
38
38
 
@@ -49,21 +49,55 @@ Here's the directory structure that `sunzi create` automatically generates:
49
49
 
50
50
  ```
51
51
  sunzi/
52
- attributes.yml ---- add custom attributes here
53
- recipes.yml ---- add remote recipes here
52
+ sunzi.yml ---- add custom attributes and remote recipes here
54
53
  remote/ ---- everything under this folder will be transferred to the remote server
55
- attributes/ ---- compiled attributes from attributes.yml at deploy (do not edit directly)
56
- env
54
+ attributes/ ---- compiled attributes from sunzi.yml at deploy (do not edit directly)
57
55
  ssh_key
58
56
  recipes/ ---- put commonly used scripts here, referred from install.sh
59
57
  ssh_key.sh
60
58
  install.sh ---- main scripts that gets run on the remote server
61
59
  ```
62
60
 
61
+ How do you pass dynamic values to a recipe?
62
+ -------------------------------------------
63
+
64
+ In the compile phase, `attributes.yml` are split into multiple files, one per attribute. We use filesystem as a sort of key-value storage so that it's easy to use from shell scripts.
65
+
66
+ The convention for argument passing to a recipe is to use `$1`, `$2`, etc. and put a comment line for each argument.
67
+
68
+ For instance, given a recipe `greeting.sh`:
69
+
70
+ ```
71
+ # Greeting
72
+ # $1: Name for goodbye
73
+ # $2: Name for hello
74
+
75
+ echo "Goodbye $1, Hello $2!"
76
+ ```
77
+
78
+ With `attributes.yml`:
79
+
80
+ ```
81
+ goodbye: Chef
82
+ hello: Sunzi
83
+ ```
84
+
85
+ Then, include the recipe in `install.sh`:
86
+
87
+ ```
88
+ source recipes/greeting.sh $(cat attributes/goodbye) $(cat attributes/hello)
89
+ ```
90
+
91
+ Now, you get the following result. Isn't it awesome?
92
+
93
+ ```
94
+ Goodbye Chef, Hello Sunzi!
95
+ ```
96
+
63
97
  Remote Recipes
64
98
  --------------
65
99
 
66
- Recipes can be retrieved remotely via HTTP. Put the URL in `recipes.yml`, and Sunzi automatically loads the content and put it into the `remote/recipes` folder.
100
+ Recipes can be retrieved remotely via HTTP. Put a URL in `recipes.yml`, and Sunzi automatically loads the content and put it into the `remote/recipes` folder.
67
101
 
68
102
  For instance, if you have the following line in `recipes.yml`,
69
103
 
@@ -76,7 +110,28 @@ rvm: https://raw.github.com/kenn/sunzi-recipes/master/ruby/rvm.sh
76
110
  Vagrant
77
111
  -------
78
112
 
79
- If you're using Sunzi with [Vagrant](http://vagrantup.com/), you need to specify the port number 2222.
113
+ If you're using Sunzi with [Vagrant](http://vagrantup.com/), make sure that you have a root access via SSH.
114
+
115
+ An easy way is to edit `Vagrantfile`:
116
+
117
+ ```ruby
118
+ Vagrant::Config.run do |config|
119
+ config.vm.provision :shell do |shell|
120
+ shell.path = "chpasswd.sh"
121
+ end
122
+ end
123
+ ```
124
+
125
+ with `chpasswd.sh`:
126
+
127
+ ```
128
+ #!/bin/bash
129
+
130
+ sudo echo 'root:vagrant' | /usr/sbin/chpasswd
131
+ ```
132
+
133
+ and now run `vagrant up`, it will change the root password to `vagrant`.
134
+
135
+ Also keep in mind that you need to specify the port number 2222.
80
136
 
81
- $ vagrant up
82
- $ sunzi deploy root@localhost 2222
137
+ $ sunzi deploy localhost:2222
data/lib/sunzi/cli.rb CHANGED
@@ -18,37 +18,31 @@ module Sunzi
18
18
  # map "c" => :create
19
19
  # map "d" => :deploy
20
20
 
21
- desc "create [PROJECT]", "Create sunzi project"
21
+ desc "create", "Create sunzi project"
22
22
  def create(project = 'sunzi')
23
23
  empty_directory project
24
24
  empty_directory "#{project}/remote"
25
25
  empty_directory "#{project}/remote/recipes"
26
- template "templates/attributes.yml", "#{project}/attributes.yml"
27
- template "templates/recipes.yml", "#{project}/recipes.yml"
26
+ template "templates/sunzi.yml", "#{project}/sunzi.yml"
28
27
  template "templates/remote/install.sh", "#{project}/remote/install.sh"
29
28
  template "templates/remote/recipes/ssh_key.sh", "#{project}/remote/recipes/ssh_key.sh"
30
29
  end
31
30
 
32
- desc "deploy [USER@HOST] [PORT]", "Deploy sunzi project"
33
- def deploy(*target)
34
- if target.empty? or !target.first.match(/@/)
35
- say shell.set_color("Usage: sunzi deploy root@example.com", :red, true)
36
- abort
37
- end
31
+ desc "deploy example.com (or user@example.com:2222)", "Deploy sunzi project"
32
+ def deploy(target)
33
+ user, host, port = parse_target(target)
34
+ endpoint = "#{user}@#{host}"
38
35
 
36
+ # compile attributes and recipes
39
37
  compile
40
38
 
41
- host, port = target
42
- port ||= 22
43
- user, domain = host.split('@')
44
-
45
39
  # The host key might change when we instantiate a new VM, so
46
40
  # we remove (-R) the old host key from known_hosts.
47
- `ssh-keygen -R #{domain} 2> /dev/null`
41
+ `ssh-keygen -R #{host} 2> /dev/null`
48
42
 
49
43
  commands = <<-EOS
50
44
  cd remote
51
- tar cz . | ssh -o 'StrictHostKeyChecking no' #{host} -p #{port} '
45
+ tar cz . | ssh -o 'StrictHostKeyChecking no' #{endpoint} -p #{port} '
52
46
  rm -rf ~/sunzi &&
53
47
  mkdir ~/sunzi &&
54
48
  cd ~/sunzi &&
@@ -73,24 +67,31 @@ module Sunzi
73
67
  desc "compile", "Compile sunzi project"
74
68
  def compile
75
69
  # Check if you're in the sunzi directory
76
- unless File.exists?('attributes.yml')
70
+ unless File.exists?('sunzi.yml')
77
71
  say shell.set_color("You must be in the sunzi folder", :red, true)
78
72
  abort
79
73
  end
80
74
 
81
- # Compile attributes.yml
82
- hash = YAML.load(File.read('attributes.yml'))
75
+ # Load sunzi.yml
76
+ hash = YAML.load(File.read('sunzi.yml'))
83
77
  empty_directory 'remote/attributes'
84
- hash.each do |key, value|
78
+ empty_directory 'remote/recipes'
79
+
80
+ # Compile attributes.yml
81
+ hash['attributes'].each do |key, value|
85
82
  File.open("remote/attributes/#{key}", 'w'){|file| file.write(value) }
86
83
  end
87
-
88
84
  # Compile recipes.yml
89
- hash = YAML.load(File.read('recipes.yml'))
90
- empty_directory 'remote/recipes'
91
- hash.each do |key, value|
85
+ hash['recipes'].each do |key, value|
92
86
  get value, "remote/recipes/#{key}.sh"
93
87
  end
94
88
  end
89
+
90
+ no_tasks do
91
+ def parse_target(target)
92
+ target.match(/(.*@)?(.*?)(:.*)?$/)
93
+ [ ($1 && $1.delete('@') || 'root'), $2, ($3 && $3.delete(':') || '22') ]
94
+ end
95
+ end
95
96
  end
96
97
  end
data/lib/sunzi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sunzi
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -1,5 +1,8 @@
1
1
  #!/bin/bash
2
2
 
3
+ # This line is necessary for automated provisioning for Debian/Ubuntu
4
+ export DEBIAN_FRONTEND=noninteractive
5
+
3
6
  # SSH key
4
7
  source recipes/ssh_key.sh $(cat attributes/ssh_key)
5
8
 
@@ -0,0 +1,7 @@
1
+ ---
2
+ attributes:
3
+ # Dynamic variables here will be compiled to individual files in remote/attributes.
4
+ ssh_key: id_rsa.pub
5
+ recipes:
6
+ # Remote recipes here will be loaded to individual files in remote/recipes.
7
+ rvm: https://raw.github.com/kenn/sunzi-recipes/master/ruby/rvm.sh
data/test/test_cli.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'test/unit'
2
+ require '../lib/sunzi'
3
+
4
+ class TestCli < Test::Unit::TestCase
5
+ def setup
6
+ @cli = Sunzi::Cli.new
7
+ end
8
+
9
+ def test_parse_target
10
+ assert_equal ['user', 'example.com', '2222'], @cli.parse_target('user@example.com:2222')
11
+ assert_equal ['root', 'example.com', '2222'], @cli.parse_target('example.com:2222')
12
+ assert_equal ['user', 'example.com', '22'], @cli.parse_target('user@example.com')
13
+ assert_equal ['root', 'example.com', '22'], @cli.parse_target('example.com')
14
+ assert_equal ['root', '192.168.0.1', '22'], @cli.parse_target('192.168.0.1')
15
+ end
16
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sunzi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-02-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
16
- requirement: &2152751920 !ruby/object:Gem::Requirement
16
+ requirement: &2152751900 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2152751920
24
+ version_requirements: *2152751900
25
25
  description: Server provisioning utility for minimalists
26
26
  email:
27
27
  - kenn.ejima@gmail.com
@@ -39,11 +39,11 @@ files:
39
39
  - lib/sunzi/base.rb
40
40
  - lib/sunzi/cli.rb
41
41
  - lib/sunzi/version.rb
42
- - lib/templates/attributes.yml
43
- - lib/templates/recipes.yml
44
42
  - lib/templates/remote/install.sh
45
43
  - lib/templates/remote/recipes/ssh_key.sh
44
+ - lib/templates/sunzi.yml
46
45
  - sunzi.gemspec
46
+ - test/test_cli.rb
47
47
  homepage: http://github.com/kenn/sunzi
48
48
  licenses: []
49
49
  post_install_message:
@@ -68,4 +68,5 @@ rubygems_version: 1.8.15
68
68
  signing_key:
69
69
  specification_version: 3
70
70
  summary: Server provisioning utility for minimalists
71
- test_files: []
71
+ test_files:
72
+ - test/test_cli.rb
@@ -1,3 +0,0 @@
1
- --- # Dynamic variables here will be compiled to individual files in remote/attributes.
2
- env: production
3
- ssh_key: id_rsa.pub
@@ -1,2 +0,0 @@
1
- --- # Remote recipes here will be loaded to individual files in remote/recipes.
2
- rvm: https://raw.github.com/kenn/sunzi-recipes/master/ruby/rvm.sh