fpm-fry 0.2.2 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/cabin/nice_output.rb +16 -1
- data/lib/fpm/fry/block_enumerator.rb +6 -3
- data/lib/fpm/fry/build_output_parser.rb +10 -5
- data/lib/fpm/fry/channel.rb +13 -0
- data/lib/fpm/fry/chroot.rb +2 -2
- data/lib/fpm/fry/client.rb +96 -12
- data/lib/fpm/fry/command.rb +15 -32
- data/lib/fpm/fry/command/cook.rb +38 -56
- data/lib/fpm/fry/detector.rb +43 -98
- data/lib/fpm/fry/docker_file.rb +60 -26
- data/lib/fpm/fry/exec.rb +76 -0
- data/lib/fpm/fry/inspector.rb +70 -0
- data/lib/fpm/fry/joined_io.rb +1 -1
- data/lib/fpm/fry/plugin/apt.rb +52 -0
- data/lib/fpm/fry/plugin/edit_staging.rb +1 -1
- data/lib/fpm/fry/plugin/env.rb +45 -0
- data/lib/fpm/fry/plugin/init.rb +71 -42
- data/lib/fpm/fry/plugin/service.rb +108 -49
- data/lib/fpm/fry/plugin/systemd.rb +75 -0
- data/lib/fpm/fry/recipe.rb +64 -23
- data/lib/fpm/fry/recipe/builder.rb +53 -20
- data/lib/fpm/fry/source.rb +41 -12
- data/lib/fpm/fry/source/{package.rb → archive.rb} +115 -35
- data/lib/fpm/fry/source/dir.rb +13 -8
- data/lib/fpm/fry/source/git.rb +81 -45
- data/lib/fpm/fry/source/patched.rb +61 -32
- data/lib/fpm/fry/tar.rb +63 -0
- data/lib/fpm/fry/templates/debian/after_remove.erb +1 -1
- data/lib/fpm/fry/templates/debian/before_remove.erb +1 -1
- data/lib/fpm/fry/ui.rb +1 -1
- data/lib/fpm/fry/with_data.rb +34 -0
- data/lib/fpm/package/docker.rb +16 -0
- metadata +82 -13
- data/lib/fpm/fry/os_db.rb +0 -36
data/lib/fpm/fry/joined_io.rb
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'fpm/fry/plugin'
|
2
|
+
module FPM::Fry::Plugin ;
|
3
|
+
|
4
|
+
# Allows adding a debian repository.
|
5
|
+
#
|
6
|
+
# @note experimental
|
7
|
+
#
|
8
|
+
# @example in a recipe
|
9
|
+
# plugin 'apt' do |apt|
|
10
|
+
# apt.repository "https://repo.varnish-cache.org/#{distribution}", "trusty", "varnish-4.1"
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
class Apt
|
14
|
+
|
15
|
+
# Adds a debian repository
|
16
|
+
#
|
17
|
+
# @param [String] url
|
18
|
+
# @param [String] distribution
|
19
|
+
# @param [String,Array<String>] components
|
20
|
+
# @param [Hash] options
|
21
|
+
def repository(url, distribution, components, options = {} )
|
22
|
+
name = "#{url}-#{distribution}".gsub(/[^a-zA-Z0-9_\-]/,'-')
|
23
|
+
source = ['deb']
|
24
|
+
source << '[trusted=yes]'
|
25
|
+
source << url
|
26
|
+
source << distribution
|
27
|
+
source << Array(components).join(' ')
|
28
|
+
@builder.before_dependencies do
|
29
|
+
@builder.bash "echo '#{source.join(' ')}' >> /etc/apt/sources.list.d/#{name}.list && apt-get update -o Dir::Etc::sourcelist='sources.list.d/#{name}.list' -o Dir::Etc::sourceparts='-' -o APT::Get::List-Cleanup='0'"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.apply(builder, &block)
|
34
|
+
if builder.flavour != "debian"
|
35
|
+
builder.logger.info('skipped apt plugin')
|
36
|
+
return
|
37
|
+
end
|
38
|
+
dsl = self.new(builder)
|
39
|
+
if block.arity == 1
|
40
|
+
block.call(dsl)
|
41
|
+
else
|
42
|
+
dsl.instance_eval(&block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def initialize(builder)
|
49
|
+
@builder = builder
|
50
|
+
end
|
51
|
+
|
52
|
+
end ; end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'fpm/fry/plugin'
|
2
|
+
# The env plugin sets global environment variables.
|
3
|
+
#
|
4
|
+
# @example add something to PATH in a recipe
|
5
|
+
# plugin 'env', 'PATH' => '$PATH:/usr/local/go/bin'
|
6
|
+
#
|
7
|
+
module FPM::Fry::Plugin::Env
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
class AddEnv < Struct.new(:env)
|
11
|
+
|
12
|
+
def call(_, df)
|
13
|
+
df[:source] << format
|
14
|
+
end
|
15
|
+
private
|
16
|
+
|
17
|
+
def format
|
18
|
+
"ENV " + env.map{|k,v| "#{k}=#{escape(v)}" }.join(" ")
|
19
|
+
end
|
20
|
+
|
21
|
+
def escape(v)
|
22
|
+
v.gsub(/([ \n\\])/,'\\\\\\1')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.apply(builder, env)
|
27
|
+
unless env.kind_of? Hash
|
28
|
+
raise FPM::Fry::WithData(
|
29
|
+
ArgumentError.new("ENV must be a Hash, got #{env.inspect}"),
|
30
|
+
documentation: 'https://github.com/xing/fpm-fry/wiki/Plugin-env'
|
31
|
+
)
|
32
|
+
end
|
33
|
+
env.each do |k,v|
|
34
|
+
k = k.to_s if k.kind_of? Symbol
|
35
|
+
unless k.kind_of?(String) && k =~ /\A[A-Z][A-Z0-9_]*\z/
|
36
|
+
raise FPM::Fry::WithData(
|
37
|
+
ArgumentError.new("environment variable names must be strings consisiting of uppercase letters, numbers and underscores, got #{k.inspect}"),
|
38
|
+
documentation: 'https://github.com/xing/fpm-fry/wiki/Plugin-env'
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
builder.recipe.dockerfile_hooks << AddEnv.new(env.dup.freeze)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/fpm/fry/plugin/init.rb
CHANGED
@@ -1,53 +1,82 @@
|
|
1
1
|
require 'fpm/fry/plugin'
|
2
|
+
# A plugin that detects the init system of a docker image.
|
3
|
+
#
|
4
|
+
# This plugin is a low-level plugin and is used by other plugins such as "service".
|
5
|
+
#
|
6
|
+
# @example in a recipe when using the image "ubuntu:16.04"
|
7
|
+
# plugin 'init'
|
8
|
+
# init.systemd? #=> true
|
9
|
+
# init.sysv? #=> false
|
2
10
|
module FPM::Fry::Plugin::Init
|
3
11
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
return 'sysv'
|
26
|
-
elsif v[0] == 6
|
27
|
-
return 'upstart'
|
28
|
-
else
|
29
|
-
return 'systemd'
|
30
|
-
end
|
31
|
-
else
|
32
|
-
raise "Unknown init system for #{d} #{v.join '.'}"
|
12
|
+
# Contains information about the init system in use.
|
13
|
+
class System
|
14
|
+
# @return [Hash<Symbol,Object>] features of the init system
|
15
|
+
attr :with
|
16
|
+
|
17
|
+
def with?(feature)
|
18
|
+
!!with[feature]
|
19
|
+
end
|
20
|
+
def sysv?
|
21
|
+
name == :sysv
|
22
|
+
end
|
23
|
+
def upstart?
|
24
|
+
name == :upstart
|
25
|
+
end
|
26
|
+
def systemd?
|
27
|
+
name == :systemd
|
28
|
+
end
|
29
|
+
private
|
30
|
+
attr :name
|
31
|
+
def initialize(name, with)
|
32
|
+
@name, @with = name, with
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
36
|
+
# @return [System] initsystem in use
|
37
|
+
def init
|
38
|
+
return @init
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def self.detect(inspector)
|
43
|
+
if inspector.exists?('/lib/systemd/systemd')
|
44
|
+
return System.new(:systemd, {})
|
45
|
+
end
|
46
|
+
if inspector.exists?('/etc/init')
|
47
|
+
return detect_upstart(inspector)
|
48
|
+
end
|
49
|
+
if inspector.exists?('/etc/init.d')
|
50
|
+
return detect_sysv(inspector)
|
49
51
|
end
|
52
|
+
return nil
|
50
53
|
end
|
51
54
|
|
55
|
+
def self.detect_upstart(inspector)
|
56
|
+
features = {
|
57
|
+
sysvcompat: inspector.exists?('/lib/init/upstart-job') ? '/lib/init/upstart-job' : false
|
58
|
+
}
|
59
|
+
return System.new(:upstart,features)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.detect_sysv(inspector)
|
63
|
+
features = {
|
64
|
+
:chkconfig => inspector.exists?('/sbin/chkconfig'),
|
65
|
+
:'update-rc.d' => inspector.exists?('/usr/sbin/update-rc.d'),
|
66
|
+
:'invoke-rc.d' => inspector.exists?('/usr/sbin/invoke-rc.d')
|
67
|
+
}
|
68
|
+
return System.new(:sysv,features)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.extended(base)
|
72
|
+
base.instance_eval do
|
73
|
+
@init ||= FPM::Fry::Plugin::Init.detect(inspector)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.apply(builder)
|
78
|
+
builder.extend(self)
|
79
|
+
return builder.init
|
80
|
+
end
|
52
81
|
|
53
82
|
end
|
@@ -24,11 +24,12 @@ module FPM::Fry::Plugin ; module Service
|
|
24
24
|
|
25
25
|
class DSL
|
26
26
|
|
27
|
+
# @return [Hash<String,Tuple<Numeric,Numeric>]
|
27
28
|
attr :limits
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
@name =
|
30
|
+
# @api private
|
31
|
+
def initialize(name)
|
32
|
+
@name = name
|
32
33
|
@command = []
|
33
34
|
@limits = {}
|
34
35
|
@user = nil
|
@@ -36,20 +37,35 @@ module FPM::Fry::Plugin ; module Service
|
|
36
37
|
@chdir = nil
|
37
38
|
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
# @overload name
|
41
|
+
# @return [String] this service's name
|
42
|
+
# @overload name( name )
|
43
|
+
# @param [String] name new name for this service
|
44
|
+
# @return [String] this service's name
|
45
|
+
def name( name = nil )
|
46
|
+
if name
|
47
|
+
@name = name
|
42
48
|
end
|
43
49
|
return @name
|
44
50
|
end
|
45
51
|
|
46
|
-
|
47
|
-
|
48
|
-
|
52
|
+
# @overload group
|
53
|
+
# @return [String] the linux user group this service should run as
|
54
|
+
# @overload group( name )
|
55
|
+
# @param [String] name new linux user group this service should run as
|
56
|
+
# @return [String] the linux user group this service should run as
|
57
|
+
def group( group = nil )
|
58
|
+
if group
|
59
|
+
@group = group
|
49
60
|
end
|
50
61
|
return @group
|
51
62
|
end
|
52
63
|
|
64
|
+
# @overload user
|
65
|
+
# @return [String] the linux user this service should run as
|
66
|
+
# @overload user( name )
|
67
|
+
# @param [String] name new linx user this service should run as
|
68
|
+
# @return [String] the linux user this service should run as
|
53
69
|
def user( n = nil )
|
54
70
|
if n
|
55
71
|
@user = n
|
@@ -57,13 +73,39 @@ module FPM::Fry::Plugin ; module Service
|
|
57
73
|
return @user
|
58
74
|
end
|
59
75
|
|
76
|
+
# Sets a limit for this service. Valid limits are:
|
77
|
+
#
|
78
|
+
# - core
|
79
|
+
# - cpu
|
80
|
+
# - data
|
81
|
+
# - fsize
|
82
|
+
# - memlock
|
83
|
+
# - msgqueue
|
84
|
+
# - nice
|
85
|
+
# - nofile
|
86
|
+
# - nproc
|
87
|
+
# - rss
|
88
|
+
# - rtprio
|
89
|
+
# - sigpending
|
90
|
+
# - stack
|
91
|
+
#
|
92
|
+
# @see http://linux.die.net/man/5/limits.conf Limits.conf manpage for limits and their meanings.
|
93
|
+
# @param [String] name see above list for valid limits
|
94
|
+
# @param [Numeric,"unlimited"] soft soft limit
|
95
|
+
# @param [Numeric,"unlimited"] hard hard limit
|
60
96
|
def limit( name, soft, hard = soft )
|
61
97
|
unless LIMITS.include? name
|
62
98
|
raise ArgumentError, "Unknown limit #{name.inspect}. Known limits are: #{LIMITS.inspect}"
|
63
99
|
end
|
64
100
|
@limits[name] = [soft,hard]
|
101
|
+
return nil
|
65
102
|
end
|
66
103
|
|
104
|
+
# @overload chdir
|
105
|
+
# @return [String,nil] working directory of the service
|
106
|
+
# @overload chdir( dir )
|
107
|
+
# @param [String] dir new working directory of the service
|
108
|
+
# @return [String] working directory of the service
|
67
109
|
def chdir( dir = nil )
|
68
110
|
if dir
|
69
111
|
@chdir = dir
|
@@ -80,76 +122,93 @@ module FPM::Fry::Plugin ; module Service
|
|
80
122
|
|
81
123
|
# @api private
|
82
124
|
def add!(builder)
|
83
|
-
|
84
|
-
init
|
125
|
+
init = builder.plugin('init')
|
126
|
+
if init.systemd?
|
127
|
+
add_systemd!(builder)
|
128
|
+
elsif init.upstart?
|
129
|
+
add_upstart!(builder)
|
130
|
+
elsif init.sysv?
|
131
|
+
add_sysv!(builder)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
private
|
135
|
+
def add_upstart!(builder)
|
136
|
+
init = builder.plugin('init')
|
85
137
|
edit = builder.plugin('edit_staging')
|
86
138
|
env = Environment.new(name, command, "", @limits, @user, @group, @chdir)
|
87
|
-
|
88
|
-
|
89
|
-
edit.
|
90
|
-
|
91
|
-
|
92
|
-
|
139
|
+
edit.add_file "/etc/init/#{name}.conf",StringIO.new( env.render('upstart.erb') )
|
140
|
+
if init.with? :sysvcompat
|
141
|
+
edit.ln_s init.with[:sysvcompat], "/etc/init.d/#{name}"
|
142
|
+
end
|
143
|
+
builder.plugin('script_helper') do |sh|
|
144
|
+
sh.after_install_or_upgrade(<<BASH)
|
93
145
|
if status #{Shellwords.shellescape name} 2>/dev/null | grep -q ' start/'; then
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
146
|
+
# It has to be stop+start because upstart doesn't pickup changes with restart.
|
147
|
+
if which invoke-rc.d >/dev/null 2>&1; then
|
148
|
+
invoke-rc.d #{Shellwords.shellescape name} stop
|
149
|
+
else
|
150
|
+
stop #{Shellwords.shellescape name}
|
151
|
+
fi
|
100
152
|
fi
|
101
153
|
if which invoke-rc.d >/dev/null 2>&1; then
|
102
|
-
|
154
|
+
invoke-rc.d #{Shellwords.shellescape name} start
|
103
155
|
else
|
104
|
-
|
156
|
+
start #{Shellwords.shellescape name}
|
105
157
|
fi
|
106
158
|
BASH
|
107
|
-
|
159
|
+
sh.before_remove_entirely(<<BASH)
|
108
160
|
if status #{Shellwords.shellescape name} 2>/dev/null | grep -q ' start/'; then
|
109
|
-
|
161
|
+
stop #{Shellwords.shellescape name}
|
110
162
|
fi
|
111
163
|
BASH
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
164
|
+
end
|
165
|
+
builder.plugin('config', FPM::Fry::Plugin::Config::IMPLICIT => true) do |co|
|
166
|
+
co.include "etc/init/#{name}.conf"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def add_sysv!(builder)
|
171
|
+
edit = builder.plugin('edit_staging')
|
172
|
+
env = Environment.new(name, command, "", @limits, @user, @group, @chdir)
|
173
|
+
edit.add_file "/etc/init.d/#{name}",StringIO.new( env.render('sysv.erb') ), chmod: '750'
|
174
|
+
builder.plugin('script_helper') do |sh|
|
175
|
+
sh.after_install_or_upgrade(<<BASH)
|
120
176
|
update-rc.d #{Shellwords.shellescape name} defaults
|
121
177
|
/etc/init.d/#{Shellwords.shellescape name} restart
|
122
178
|
BASH
|
123
|
-
|
179
|
+
sh.before_remove_entirely(<<BASH)
|
124
180
|
/etc/init.d/#{Shellwords.shellescape name} stop
|
125
181
|
update-rc.d -f #{Shellwords.shellescape name} remove
|
126
182
|
BASH
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
183
|
+
end
|
184
|
+
builder.plugin('config', FPM::Fry::Plugin::Config::IMPLICIT => true) do |co|
|
185
|
+
co.include "etc/init.d/#{name}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def add_systemd!(builder)
|
190
|
+
edit = builder.plugin('edit_staging')
|
191
|
+
env = Environment.new(name, command, "", @limits, @user, @group, @chdir)
|
192
|
+
edit.add_file "/lib/systemd/system/#{name}.service", StringIO.new( env.render('systemd.erb') ), chmod: '644'
|
193
|
+
builder.plugin('script_helper') do |sh|
|
194
|
+
sh.after_install_or_upgrade(<<BASH)
|
135
195
|
systemctl preset #{Shellwords.shellescape name}.service
|
136
196
|
if systemctl is-enabled --quiet #{Shellwords.shellescape name}.service ; then
|
137
|
-
|
138
|
-
|
197
|
+
systemctl --system daemon-reload
|
198
|
+
systemctl restart #{Shellwords.shellescape name}.service
|
139
199
|
fi
|
140
200
|
BASH
|
141
|
-
|
201
|
+
sh.before_remove_entirely(<<BASH)
|
142
202
|
systemctl disable --now #{Shellwords.shellescape name}.service
|
143
203
|
BASH
|
144
204
|
|
145
|
-
end
|
146
205
|
end
|
147
206
|
end
|
148
207
|
|
149
208
|
end
|
150
209
|
|
151
210
|
def self.apply(builder, &block)
|
152
|
-
d = DSL.new
|
211
|
+
d = DSL.new(builder.name)
|
153
212
|
if !block
|
154
213
|
raise ArgumentError, "service plugin requires a block"
|
155
214
|
elsif block.arity == 1
|