sunzi 0.2.1 → 0.3.0
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.
- 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