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 +66 -11
- data/lib/sunzi/cli.rb +24 -23
- data/lib/sunzi/version.rb +1 -1
- data/lib/templates/remote/install.sh +3 -0
- data/lib/templates/sunzi.yml +7 -0
- data/test/test_cli.rb +16 -0
- metadata +7 -6
- data/lib/templates/attributes.yml +0 -3
- data/lib/templates/recipes.yml +0 -2
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,
|
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
|
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
|
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
|
-
|
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
|
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
|
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
|
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
|
-
$
|
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
|
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/
|
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
|
33
|
-
def deploy(
|
34
|
-
|
35
|
-
|
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 #{
|
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' #{
|
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?('
|
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
|
-
#
|
82
|
-
hash = YAML.load(File.read('
|
75
|
+
# Load sunzi.yml
|
76
|
+
hash = YAML.load(File.read('sunzi.yml'))
|
83
77
|
empty_directory 'remote/attributes'
|
84
|
-
|
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
|
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
@@ -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.
|
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: &
|
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: *
|
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
|
data/lib/templates/recipes.yml
DELETED