necktie 1.0.4 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/README.rdoc +16 -19
- data/example/tasks/db.rb +3 -3
- data/lib/necktie.rb +1 -0
- data/lib/necktie/application.rb +7 -6
- data/lib/necktie/capistrano.rb +1 -1
- data/lib/necktie/erb.rb +66 -0
- data/lib/necktie/files.rb +58 -35
- data/lib/necktie/gems.rb +17 -15
- data/necktie.gemspec +1 -1
- metadata +4 -3
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
1.0.5 (2009-11-13)
|
2
|
+
* Added erb: a file task that creates a file form an ERB template.
|
3
|
+
* Changed: The write and update file methods now perform atomic writes (create
|
4
|
+
temporary file, rename to desired path).
|
5
|
+
* Fix: MySQL examples used task instead of file task.
|
6
|
+
|
1
7
|
1.0.4 (2009-11-4)
|
2
8
|
* When used with -U option and no other argument, necktie command updates the
|
3
9
|
local repo but does not run any task.
|
data/README.rdoc
CHANGED
@@ -1,29 +1,22 @@
|
|
1
|
-
|
1
|
+
= Minimalistic server configuration tool
|
2
2
|
|
3
|
+
Necktie is tool for running configuration tasks: setting up new servers and
|
4
|
+
upgrading production servers. You can use it to manage services, mount
|
5
|
+
volumes, change configuration, manage cronjobs, etc.
|
3
6
|
|
4
|
-
|
5
|
-
|
6
|
-
Necktie runs a set of scripts (or configuration tasks) that can create and edit
|
7
|
-
files, install and setup services, mount volumes, and basically anything you
|
8
|
-
can script with Ruby and a shell.
|
9
|
-
|
10
|
-
To use Necktie:
|
11
|
-
- Write your Necktie tasks
|
12
|
-
- Include support files (config, binaries, etc)
|
13
|
-
- git push && cap necktie
|
14
|
-
|
15
|
-
I use it to:
|
16
|
-
|
17
|
-
- gem install, apt-get
|
18
|
-
- Configure Nginx, install and setup Unicorn
|
19
|
-
- Change memcached configuration from default
|
20
|
-
- Setup MySQL to use a mounted (EBS) volume
|
21
|
-
- Install and update cron scripts
|
7
|
+
http://19.media.tumblr.com/tumblr_kspcaa4Djr1qzo4cfo1_250.jpg
|
22
8
|
|
23
9
|
To install Necktie:
|
24
10
|
|
25
11
|
$ gem install necktie --source http://gemcutter.org
|
26
12
|
|
13
|
+
To use Necktie:
|
14
|
+
1. Write a Necktie file with configurtaion tasks
|
15
|
+
2. Include any support files: config, scripts, binaries, etc
|
16
|
+
3. git push && cap necktie
|
17
|
+
|
18
|
+
Introduction to Necktie: http://blog.labnotes.org/2009/11/04/necktie-dress-to-impress/
|
19
|
+
|
27
20
|
|
28
21
|
== Tasking
|
29
22
|
|
@@ -215,4 +208,8 @@ Includes Session, created by Ara T. Howard and released under the Ruby License
|
|
215
208
|
http://raa.ruby-lang.org/project/session
|
216
209
|
http://www.codeforpeople.com/lib/ruby/session
|
217
210
|
|
211
|
+
Atomic file write adapted from Rails.
|
212
|
+
|
213
|
+
ERB task adapted from Luke Bayes http://gist.github.com/215270.
|
214
|
+
|
218
215
|
Developed for managing EC2 instances for http://apartly.com
|
data/example/tasks/db.rb
CHANGED
@@ -3,13 +3,13 @@ file "/etc/cron.hourly/snapshot"=>"etc/cron/snapshot" do
|
|
3
3
|
chmod 0755, "/etc/cron.hourly/snapshot"
|
4
4
|
end
|
5
5
|
|
6
|
-
|
6
|
+
file "/vol" do
|
7
7
|
# Assumes we attach EBS volume to /dev/sdh, formatted it to XFS, mounted to /vol.
|
8
8
|
append "/etc/fstab", "/dev/sdh /vol xfs noatime,nobarrier 0 0\n" unless read("/etc/fstab")["/dev/sdh "]
|
9
9
|
sh "mount /vol"
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
file "/etc/mysql"=>"/vol" do
|
13
13
|
# Mount the respective MySQL directories. Make sure they exist on your EBS volume first, see:
|
14
14
|
# http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1663
|
15
15
|
mounts = { "/vol/etc/mysql"=>"/etc/mysql",
|
@@ -23,7 +23,7 @@ task "/etc/mysql"=>"/vol" do
|
|
23
23
|
chmod 0755, "/etc/mysql/debian-start"
|
24
24
|
end
|
25
25
|
|
26
|
-
task
|
26
|
+
task :mysql=>"/etc/mysql" do
|
27
27
|
services.start "mysql" unless services.running?("mysql")
|
28
28
|
end
|
29
29
|
|
data/lib/necktie.rb
CHANGED
data/lib/necktie/application.rb
CHANGED
@@ -10,7 +10,6 @@ module Necktie
|
|
10
10
|
@rakefiles = ["Necktie", "necktie", "Necktie.rb", "necktie.rb"]
|
11
11
|
options.nosearch = true
|
12
12
|
options.env = "production"
|
13
|
-
@syslog = Syslog.open("necktie")
|
14
13
|
end
|
15
14
|
|
16
15
|
def run
|
@@ -31,7 +30,7 @@ module Necktie
|
|
31
30
|
sh "git checkout #{options.ref}" if options.ref
|
32
31
|
@sha = `git rev-parse --verify HEAD --short`.strip
|
33
32
|
puts "(in #{Dir.pwd}, head is #{@sha}, environment is #{options.env})"
|
34
|
-
syslog :info, "environment is
|
33
|
+
syslog :info, "environment is %s", options.env
|
35
34
|
|
36
35
|
load_rakefile
|
37
36
|
top_level unless options.pull && ARGV.empty?
|
@@ -141,8 +140,10 @@ module Necktie
|
|
141
140
|
load_imports
|
142
141
|
end
|
143
142
|
|
144
|
-
def syslog(level, message)
|
145
|
-
|
143
|
+
def syslog(level, message, *args)
|
144
|
+
Syslog.open("necktie") do |s|
|
145
|
+
s.send level, "[#{@sha}] #{message}", *args
|
146
|
+
end
|
146
147
|
end
|
147
148
|
|
148
149
|
end
|
@@ -158,10 +159,10 @@ end
|
|
158
159
|
class Rake::Task #:nodoc:
|
159
160
|
alias :execute_without_syslog :execute
|
160
161
|
def execute(args=nil)
|
161
|
-
application.syslog :info, "execute:
|
162
|
+
application.syslog :info, "execute: %s", name
|
162
163
|
execute_without_syslog args
|
163
164
|
rescue
|
164
|
-
application.syslog :err, "
|
165
|
+
application.syslog :err, "%s: %s: %s", $!.backtrace.first, $!.class.name, $!.to_s
|
165
166
|
raise
|
166
167
|
end
|
167
168
|
end
|
data/lib/necktie/capistrano.rb
CHANGED
@@ -13,7 +13,7 @@ Capistrano::Configuration.instance.load do
|
|
13
13
|
desc "[internal] Pull updates from Git"
|
14
14
|
task :pull do
|
15
15
|
fail "You need to set :necktie_url, <git_url>" unless necktie_url
|
16
|
-
sudo "necktie --source #{necktie_url} --update"
|
16
|
+
sudo "necktie --environment #{fetch(:rails_env, "production")} --source #{necktie_url} --update"
|
17
17
|
end
|
18
18
|
|
19
19
|
desc "[internal] Run necktie upgrade"
|
data/lib/necktie/erb.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require "erb"
|
2
|
+
|
3
|
+
module Necktie
|
4
|
+
|
5
|
+
# Rake task that makes it stupid-easy to render ERB templates to disk. Just
|
6
|
+
# add parameters to the yielded object, and they will be available to your
|
7
|
+
# Template.
|
8
|
+
#
|
9
|
+
# Loosely based on: http://gist.github.com/215270
|
10
|
+
class ErbTask < Rake::FileTask
|
11
|
+
|
12
|
+
# Path to the input ERB template. This value will default to the value of
|
13
|
+
# "#{output}.erb"
|
14
|
+
attr_accessor :template
|
15
|
+
|
16
|
+
def initialize(name, app) # :nodoc:
|
17
|
+
super
|
18
|
+
@output = name
|
19
|
+
@template = "#{name}.erb"
|
20
|
+
@values = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute(*args)
|
24
|
+
super
|
25
|
+
content = File.read(template)
|
26
|
+
result = ERB.new(content, nil, '>').result(binding)
|
27
|
+
write name, result
|
28
|
+
puts " * Created ERB output at: #{name}" if application.options.trace
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.define_task(args)
|
32
|
+
task = super
|
33
|
+
if task.is_a?(Necktie::ErbTask)
|
34
|
+
yield task if block_given?
|
35
|
+
task.prerequisites << file(task.template)
|
36
|
+
end
|
37
|
+
return task
|
38
|
+
end
|
39
|
+
|
40
|
+
def method_missing(method, *params, &block)
|
41
|
+
if method.to_s[/^(.*)=$/, 1]
|
42
|
+
return @values[$1] = params.first
|
43
|
+
elsif @values.keys.include?(method.to_s)
|
44
|
+
return @values[method.to_s]
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Rake task that makes it stupid-easy to render ERB templates to disk. Just add
|
54
|
+
# parameters to the yielded object, and they will be available to your
|
55
|
+
# Template.
|
56
|
+
#
|
57
|
+
# For example:
|
58
|
+
# erb 'config/SomeFile.xml' do |t|
|
59
|
+
# t.param1 = 'value'
|
60
|
+
# t.other_param = 'other value'
|
61
|
+
# t.another_param = ['a', 'b', 'c']
|
62
|
+
# t.template = 'config/SomeFile.xml.erb' # Optional - will automatically look here...
|
63
|
+
# end
|
64
|
+
def erb(args, &block)
|
65
|
+
Necktie::ErbTask.define_task(args, &block)
|
66
|
+
end
|
data/lib/necktie/files.rb
CHANGED
@@ -1,44 +1,67 @@
|
|
1
|
-
|
2
|
-
# Return the contents of the file (same as File.read).
|
3
|
-
def read(name)
|
4
|
-
File.read(name)
|
5
|
-
end
|
1
|
+
require "tempfile"
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
contents ||= yield
|
13
|
-
File.open name, "w" do |f|
|
14
|
-
f.write contents
|
3
|
+
module Necktie
|
4
|
+
module Files
|
5
|
+
# Return the contents of the file (same as File.read).
|
6
|
+
def read(name)
|
7
|
+
File.read(name)
|
15
8
|
end
|
16
|
-
end
|
17
9
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
10
|
+
# Writes contents to a new file, or overwrites existing file. Takes string
|
11
|
+
# as second argument, or yields to block. For example:
|
12
|
+
#
|
13
|
+
# write "/etc/mailname", "example.com"
|
14
|
+
# write("/var/run/bowtie.pid") { Process.pid }
|
15
|
+
#
|
16
|
+
# This method performs an atomic write using TMPDIR or (/tmp) as the
|
17
|
+
# temporary directory and renaming the file over to the new location.
|
18
|
+
# Ownership and premission are retained if replacing existing file.
|
19
|
+
def write(name, contents = nil)
|
20
|
+
temp = Tempfile.new(File.basename(name))
|
21
|
+
temp.write contents || yield
|
22
|
+
temp.close
|
23
|
+
|
24
|
+
begin
|
25
|
+
# Get original file permissions
|
26
|
+
stat = File.stat(name)
|
27
|
+
rescue Errno::ENOENT
|
28
|
+
# No old permissions, write a temp file to determine the defaults
|
29
|
+
stat_check = File.join(File.dirname(name), ".permissions_check.#{Thread.current.object_id}.#{Process.pid}.#{rand(1000000)}")
|
30
|
+
File.open(stat_check, "w") { }
|
31
|
+
stat = File.stat(stat_check)
|
32
|
+
File.unlink stat_check
|
33
|
+
end
|
34
|
+
|
35
|
+
# Overwrite original file with temp file (tries rename, if that fails, copies).
|
36
|
+
FileUtils.mv temp.path, name
|
37
|
+
|
38
|
+
# Set correct permissions on new file
|
39
|
+
File.chown stat.uid, stat.gid, name
|
40
|
+
File.chmod stat.mode, name
|
25
41
|
end
|
26
|
-
end
|
27
42
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
contents = contents.sub(from, to)
|
37
|
-
else
|
38
|
-
contents = yield(contents)
|
43
|
+
# Append contents to a file, creating it if necessary. Takes string as
|
44
|
+
# second argument, or yields to block. For example:
|
45
|
+
# append "/etc/fstab", "/dev/sdh /vol xfs\n" unless read("/etc/fstab")["/dev/sdh "]
|
46
|
+
def append(name, contents = nil)
|
47
|
+
contents ||= yield
|
48
|
+
File.open name, "a" do |f|
|
49
|
+
f.write contents
|
50
|
+
end
|
39
51
|
end
|
40
|
-
|
41
|
-
|
52
|
+
|
53
|
+
# Updates a file: read contents, substitue and write it back. Takes two
|
54
|
+
# arguments for substitution, or yields to block. These two are equivalent:
|
55
|
+
# update "/etc/memcached.conf", /^-l 127.0.0.1/, "-l 0.0.0.0"
|
56
|
+
# update("/etc/memcached.conf") { |s| s.sub(/^-l 127.0.0.1/, "-l 0.0.0.0") }
|
57
|
+
def update(name, from = nil, to = nil)
|
58
|
+
contents = File.read(name)
|
59
|
+
if from && to
|
60
|
+
contents = contents.sub(from, to)
|
61
|
+
else
|
62
|
+
contents = yield(contents)
|
63
|
+
end
|
64
|
+
write name, contents
|
42
65
|
end
|
43
66
|
end
|
44
67
|
end
|
data/lib/necktie/gems.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
1
|
require "rubygems/dependency_installer"
|
2
2
|
|
3
|
-
module Necktie
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
3
|
+
module Necktie
|
4
|
+
module Gems
|
5
|
+
# Installs the specified gem, if not already installed. First argument is the
|
6
|
+
# name of the gem, or file containing the gem. Second argument is version requirement.
|
7
|
+
# For example:
|
8
|
+
# install_gem "unicorn", "~>0.93"
|
9
|
+
#
|
10
|
+
# Dir["gems/*.gem"].each do |gem|
|
11
|
+
# install_gem gem
|
12
|
+
# end
|
13
|
+
def install_gem(name, version = nil)
|
14
|
+
installer = Gem::DependencyInstaller.new
|
15
|
+
spec = installer.find_spec_by_name_and_version(name, version).first.first
|
16
|
+
if Gem::SourceIndex.from_installed_gems.find_name(spec.name, spec.version).empty?
|
17
|
+
puts " ** Installing the gem #{spec.name} #{spec.version}"
|
18
|
+
installer.install name, version
|
19
|
+
end
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
data/necktie.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: necktie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Assaf Arkin
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-13 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -26,6 +26,7 @@ files:
|
|
26
26
|
- bin/necktie
|
27
27
|
- lib/necktie/application.rb
|
28
28
|
- lib/necktie/capistrano.rb
|
29
|
+
- lib/necktie/erb.rb
|
29
30
|
- lib/necktie/files.rb
|
30
31
|
- lib/necktie/gems.rb
|
31
32
|
- lib/necktie/rush.rb
|
@@ -255,7 +256,7 @@ licenses: []
|
|
255
256
|
post_install_message:
|
256
257
|
rdoc_options:
|
257
258
|
- --title
|
258
|
-
- Necktie 1.0.
|
259
|
+
- Necktie 1.0.5
|
259
260
|
- --main
|
260
261
|
- README.rdoc
|
261
262
|
- --webcvs
|