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 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