bixby-provision 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +29 -0
- data/Gemfile.lock +192 -0
- data/Rakefile +13 -0
- data/VERSION +1 -0
- data/Vagrantfile +64 -0
- data/bin/bixby-provision +6 -0
- data/bixby-provision.gemspec +113 -0
- data/lib/bixby-provision.rb +2 -0
- data/lib/bixby/provision.rb +65 -0
- data/lib/bixby/provision/app.rb +34 -0
- data/lib/bixby/provision/dsl.rb +23 -0
- data/lib/bixby/provision/dsl/base.rb +76 -0
- data/lib/bixby/provision/dsl/bundler.rb +18 -0
- data/lib/bixby/provision/dsl/config.rb +124 -0
- data/lib/bixby/provision/dsl/dir.rb +34 -0
- data/lib/bixby/provision/dsl/file.rb +108 -0
- data/lib/bixby/provision/dsl/inventory.rb +18 -0
- data/lib/bixby/provision/dsl/meteor.rb +30 -0
- data/lib/bixby/provision/dsl/nodejs.rb +73 -0
- data/lib/bixby/provision/dsl/npm.rb +18 -0
- data/lib/bixby/provision/dsl/ntp.rb +41 -0
- data/lib/bixby/provision/dsl/packager/apt.rb +46 -0
- data/lib/bixby/provision/dsl/packager/base.rb +11 -0
- data/lib/bixby/provision/dsl/packager/npm.rb +67 -0
- data/lib/bixby/provision/dsl/packager/yum.rb +100 -0
- data/lib/bixby/provision/dsl/packager/yum/epel.rb +71 -0
- data/lib/bixby/provision/dsl/packager/yum/mongodb.rb +43 -0
- data/lib/bixby/provision/dsl/ruby.rb +21 -0
- data/lib/bixby/provision/dsl/run_control.rb +49 -0
- data/lib/bixby/provision/dsl/scm.rb +34 -0
- data/lib/bixby/provision/dsl/scm/base.rb +11 -0
- data/lib/bixby/provision/dsl/scm/git.rb +89 -0
- data/lib/bixby/provision/dsl/scm/svn.rb +11 -0
- data/lib/bixby/provision/dsl/service.rb +56 -0
- data/lib/bixby/provision/dsl/services/base.rb +11 -0
- data/lib/bixby/provision/dsl/services/init.rb +40 -0
- data/lib/bixby/provision/dsl/system.rb +53 -0
- data/lib/bixby/provision/dsl/util/file.rb +100 -0
- data/lib/bixby/provision/dsl/variable.rb +27 -0
- data/lib/bixby/provision/manifest.rb +49 -0
- data/lib/bixby/provision/manifest/dsl_proxy.rb +17 -0
- data/manifest.rb +31 -0
- data/tasks/coverage.rake +2 -0
- data/tasks/jeweler.rake +21 -0
- data/tasks/test.rake +5 -0
- data/tasks/yard.rake +2 -0
- metadata +244 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
module Bixby
|
3
|
+
module Provision
|
4
|
+
|
5
|
+
class App
|
6
|
+
|
7
|
+
include Bixby::ScriptUtil
|
8
|
+
include Bixby::Log
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
end
|
12
|
+
|
13
|
+
def run!
|
14
|
+
file = ARGV.shift
|
15
|
+
|
16
|
+
if file == "--" then
|
17
|
+
logger.info "reading manifest on STDIN"
|
18
|
+
str = read_stdin()
|
19
|
+
t = Tempfile.new("bixby-provision-")
|
20
|
+
t.write(str)
|
21
|
+
t.close
|
22
|
+
file = t.path
|
23
|
+
else
|
24
|
+
file = File.expand_path(file)
|
25
|
+
logger.info "reading manifest from file #{file}"
|
26
|
+
end
|
27
|
+
|
28
|
+
Bixby::Provision::Manifest.new(file)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require "semver"
|
3
|
+
|
4
|
+
require "bixby/provision/dsl/base"
|
5
|
+
require "bixby/provision/dsl/run_control"
|
6
|
+
require "bixby/provision/dsl/variable"
|
7
|
+
require "bixby/provision/dsl/config"
|
8
|
+
|
9
|
+
require "bixby/provision/dsl/system"
|
10
|
+
require "bixby/provision/dsl/service"
|
11
|
+
|
12
|
+
require "bixby/provision/dsl/file"
|
13
|
+
require "bixby/provision/dsl/dir"
|
14
|
+
require "bixby/provision/dsl/scm"
|
15
|
+
|
16
|
+
require "bixby/provision/dsl/inventory"
|
17
|
+
|
18
|
+
require "bixby/provision/dsl/ntp"
|
19
|
+
require "bixby/provision/dsl/nodejs"
|
20
|
+
require "bixby/provision/dsl/npm"
|
21
|
+
require "bixby/provision/dsl/meteor"
|
22
|
+
require "bixby/provision/dsl/ruby"
|
23
|
+
require "bixby/provision/dsl/bundler"
|
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
require "bixby/provision/dsl/util/file"
|
3
|
+
|
4
|
+
module Bixby
|
5
|
+
module Provision
|
6
|
+
|
7
|
+
class Base
|
8
|
+
|
9
|
+
include Bixby::Log
|
10
|
+
extend Bixby::Log
|
11
|
+
include Bixby::ScriptUtil
|
12
|
+
include Bixby::Provision::Util::File
|
13
|
+
|
14
|
+
PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
15
|
+
|
16
|
+
attr_accessor :manifest, :proxy
|
17
|
+
|
18
|
+
def initialize(obj=nil)
|
19
|
+
if obj.kind_of? Base then
|
20
|
+
@manifest = obj.manifest
|
21
|
+
@proxy = obj.proxy
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def tap(&block)
|
26
|
+
self.instance_eval(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_uid(user)
|
30
|
+
return user if user.nil? or user.kind_of? Fixnum
|
31
|
+
return user.to_i if user =~ /^[0-9]+$/ # convert to int, e.g. "500"
|
32
|
+
begin
|
33
|
+
return Etc.getpwnam(user).uid
|
34
|
+
rescue ArgumentError => ex
|
35
|
+
# TODO raise
|
36
|
+
logger.warn("Username '#{user}' was invalid: #{ex.message}")
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_user(uid)
|
42
|
+
begin
|
43
|
+
return Etc.getpwuid(uid).name
|
44
|
+
rescue ArgumentError => ex
|
45
|
+
# TODO raise
|
46
|
+
logger.warn("Username '#{user}' was invalid: #{ex.message}")
|
47
|
+
end
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_gid(group)
|
52
|
+
return group if group.nil? or group.kind_of? Fixnum
|
53
|
+
return group.to_i if group =~ /^[0-9]+$/ # convert to int, e.g. "500"
|
54
|
+
begin
|
55
|
+
return Etc.getgrnam(group).gid
|
56
|
+
rescue ArgumentError => ex
|
57
|
+
# TODO raise
|
58
|
+
logger.warn("Group '#{group}' was invalid: #{ex.message}")
|
59
|
+
end
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_group(gid)
|
64
|
+
begin
|
65
|
+
return Etc.getgrgid(gid).name
|
66
|
+
rescue ArgumentError => ex
|
67
|
+
# TODO raise
|
68
|
+
logger.warn("Group '#{group}' was invalid: #{ex.message}")
|
69
|
+
end
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
|
2
|
+
require "tilt"
|
3
|
+
|
4
|
+
module Bixby
|
5
|
+
module Provision
|
6
|
+
|
7
|
+
class Config < Base
|
8
|
+
|
9
|
+
EXPORTS = []
|
10
|
+
|
11
|
+
def file(dest, opts={})
|
12
|
+
|
13
|
+
# By default, attempt to preserve ownership and mode if none are given in opts
|
14
|
+
opts[:preserve] = true if !opts.include? :preserve
|
15
|
+
|
16
|
+
dest_file = File.expand_path(dest)
|
17
|
+
if File.exists? dest_file then
|
18
|
+
stat = File.stat(dest_file)
|
19
|
+
old_owner = "#{stat.uid}:#{stat.gid}"
|
20
|
+
old_mode = stat.mode
|
21
|
+
else
|
22
|
+
old_owner = old_mode = nil
|
23
|
+
dir.create(File.dirname(dest_file))
|
24
|
+
end
|
25
|
+
|
26
|
+
source = resolve_file(opts.delete(:source), dest_file)
|
27
|
+
if source.nil? then
|
28
|
+
# TODO raise
|
29
|
+
end
|
30
|
+
|
31
|
+
template = get_template(source)
|
32
|
+
if template.nil? then
|
33
|
+
|
34
|
+
if sha256sum(dest_file) == sha256sum(source) then
|
35
|
+
logger.info "[config] skipping #{dest_file}: sha256sum matches"
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
# just copy the file over
|
40
|
+
if File.writable?(dest_file) then
|
41
|
+
logger.info "[config] copying #{source} to #{dest}"
|
42
|
+
FileUtils.cp(source, dest_file)
|
43
|
+
else
|
44
|
+
logger.info "[config] copying #{source} to #{dest} (as root)"
|
45
|
+
logged_sudo("cp #{source} #{dest_file}")
|
46
|
+
end
|
47
|
+
|
48
|
+
else
|
49
|
+
# use template
|
50
|
+
logger.info "[config] rendering template #{source}"
|
51
|
+
str = template.render(self.proxy)
|
52
|
+
|
53
|
+
if (File.exists? dest_file and File.writable? dest_file) or
|
54
|
+
File.writable? File.dirname(dest_file) then
|
55
|
+
|
56
|
+
# write directly
|
57
|
+
File.open(dest_file, 'w') { |f| f.write str }
|
58
|
+
|
59
|
+
else
|
60
|
+
# write to temp and mv into place
|
61
|
+
t = Tempfile.new("bixby-provision-")
|
62
|
+
t.write str
|
63
|
+
t.close
|
64
|
+
logged_sudo("mv #{t.path} #{dest_file}")
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
# set correct ownership/mode
|
70
|
+
owner = opts[:chown]
|
71
|
+
mode = opts[:chmod]
|
72
|
+
if opts[:preserve] then
|
73
|
+
owner ||= old_owner
|
74
|
+
mode ||= old_mode
|
75
|
+
end
|
76
|
+
chown(dest_file, owner)
|
77
|
+
chmod(dest_file, mode)
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def get_template(file)
|
85
|
+
return nil if File.basename(file) !~ /\..*$/
|
86
|
+
begin
|
87
|
+
return Tilt.new(file)
|
88
|
+
rescue RuntimeError => ex
|
89
|
+
if ex.message =~ /No template engine registered/ then
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
raise ex
|
93
|
+
end
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def resolve_file(file, dest)
|
98
|
+
if file.nil? then
|
99
|
+
return nil if dest.nil?
|
100
|
+
# look for a file with the same name as in dest
|
101
|
+
file = File.basename(dest)
|
102
|
+
end
|
103
|
+
|
104
|
+
f = File.expand_path(file)
|
105
|
+
return f if File.exists? f
|
106
|
+
|
107
|
+
# search for it in file/
|
108
|
+
f = File.expand_path("../files/#{file}", self.manifest.filename)
|
109
|
+
return f if File.exists? f
|
110
|
+
|
111
|
+
# look for the given file with any extension
|
112
|
+
files = Dir.glob("#{f}.*")
|
113
|
+
return files.shift if files.size == 1
|
114
|
+
|
115
|
+
return nil
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
register_dsl Config
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
module Bixby
|
3
|
+
module Provision
|
4
|
+
|
5
|
+
class DirDSL < Base
|
6
|
+
|
7
|
+
EXPORTS = [:mkdir, :mkdir_p]
|
8
|
+
|
9
|
+
def create(path, opts={})
|
10
|
+
logger.info "[dir] ensuring #{path} exists"
|
11
|
+
path = File.expand_path(path)
|
12
|
+
begin
|
13
|
+
FileUtils.mkdir_p(path) if !File.exists? path
|
14
|
+
chown(path, opts[:chown])
|
15
|
+
chmod(path, opts[:chmod])
|
16
|
+
rescue Errno::EACCES => ex
|
17
|
+
logger.info "[dir] permission denied, trying again with sudo"
|
18
|
+
logged_sudo("mkdir -p #{path}")
|
19
|
+
chown(path, opts[:chown])
|
20
|
+
chmod(path, opts[:chmod])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
alias_method :mkdir, :create
|
24
|
+
alias_method :mkdir_p, :create
|
25
|
+
|
26
|
+
def recreate(path, opts={})
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
register_dsl DirDSL, "dir"
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
|
2
|
+
module Bixby
|
3
|
+
module Provision
|
4
|
+
|
5
|
+
class FileDSL < Base
|
6
|
+
|
7
|
+
EXPORTS = [:symlink, :copy, :cp]
|
8
|
+
|
9
|
+
def create(opts={})
|
10
|
+
end
|
11
|
+
|
12
|
+
def symlink(source, dest)
|
13
|
+
source = File.expand_path(source)
|
14
|
+
dest = File.expand_path(dest)
|
15
|
+
|
16
|
+
if File.symlink?(dest) && File.realpath(dest) == source then
|
17
|
+
logger.info "[file] #{dest} already points to #{source}"
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
logger.info "[file] creating symlink: #{dest} -> #{source}"
|
22
|
+
|
23
|
+
if File.writable? File.dirname(dest) then
|
24
|
+
FileUtils.symlink(source, dest)
|
25
|
+
else
|
26
|
+
# as root
|
27
|
+
logged_sudo("ln -sf #{source} #{dest}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def copy(*args)
|
32
|
+
if args.last.kind_of? Hash then
|
33
|
+
opts = args.pop
|
34
|
+
else
|
35
|
+
opts = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
dest = File.expand_path(args.pop)
|
39
|
+
if args.length > 1 || args.first.include?("*") then
|
40
|
+
dest_dir = dest
|
41
|
+
self.dir.mkdir(dest_dir)
|
42
|
+
elsif File.directory? dest then
|
43
|
+
dest_dir = dest
|
44
|
+
else
|
45
|
+
dest_dir = File.dirname(dest)
|
46
|
+
self.dir.mkdir(dest_dir)
|
47
|
+
end
|
48
|
+
|
49
|
+
args = args.map{ |s| File.expand_path(s) }
|
50
|
+
files = args.join(' ')
|
51
|
+
|
52
|
+
flags = ""
|
53
|
+
flags += "-r" if (opts[:recurse] || opts[:recursively])
|
54
|
+
flags += " -f" if opts[:force]
|
55
|
+
|
56
|
+
if File.writable? dest_dir then
|
57
|
+
dest = args.size > 1 ? dest_dir : dest
|
58
|
+
logger.info "[file] copying #{files} -> #{dest}"
|
59
|
+
logged_systemu("cp #{flags} #{files} #{dest}")
|
60
|
+
|
61
|
+
else
|
62
|
+
# as root
|
63
|
+
dest = args.size > 1 ? dest_dir : dest
|
64
|
+
logger.info "[file] copying #{files} -> #{dest}"
|
65
|
+
logged_sudo("cp #{flags} #{files} #{dest}")
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
return if !(opts[:chmod] or opts[:chown])
|
70
|
+
|
71
|
+
# need to take care to translate src args to dest path
|
72
|
+
# can't simply pass args into chmod/chown for this reason,
|
73
|
+
# since we want to affect the newly copied files
|
74
|
+
|
75
|
+
if args.length > 1 || args.first.include?("*") then
|
76
|
+
# work on all source files
|
77
|
+
args.each do |s|
|
78
|
+
if s.include? "*" then
|
79
|
+
Dir.glob(s).each{ |e|
|
80
|
+
f = File.join(dest_dir, File.basename(e))
|
81
|
+
chmod(f, opts[:chmod]) if opts[:chmod]
|
82
|
+
chown(f, opts[:chown]) if opts[:chown]
|
83
|
+
}
|
84
|
+
else
|
85
|
+
f = File.join(dest_dir, File.basename(e))
|
86
|
+
chmod(f, opts[:chmod]) if opts[:chmod]
|
87
|
+
chown(f, opts[:chown]) if opts[:chown]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
else
|
92
|
+
# work on a single file
|
93
|
+
if File.directory? dest then
|
94
|
+
dest = File.join(dest, File.basename(args.first))
|
95
|
+
end
|
96
|
+
|
97
|
+
chmod(dest, opts[:chmod]) if opts[:chmod]
|
98
|
+
chown(dest, opts[:chown]) if opts[:chown]
|
99
|
+
end
|
100
|
+
|
101
|
+
end # copy
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
register_dsl FileDSL, "file"
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|