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.
@@ -11,7 +11,7 @@ module FPM; module Fry
11
11
  end
12
12
 
13
13
  # Reads length bytes or all if length is nil.
14
- # @param [Numeric, nil] length
14
+ # @param [Numeric, nil] len
15
15
  # @return [String] resulting bytes
16
16
  def read( len = nil )
17
17
  buf = []
@@ -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
@@ -4,7 +4,7 @@ require 'fileutils'
4
4
  # A plugin to edit the final build results.
5
5
  # @example Add a file
6
6
  # plugin 'edit_staging' do
7
- # add_file '/a_file'
7
+ # add_file '/a_file', 'some content'
8
8
  # end
9
9
  module FPM::Fry::Plugin::EditStaging
10
10
 
@@ -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
@@ -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
- def self.detect_init(variables)
5
- if variables[:init]
6
- return variables[:init]
7
- end
8
- d = variables[:distribution]
9
- v = variables[:distribution_version].split('.').map(&:to_i)
10
- case(d)
11
- when 'debian'
12
- if v[0] < 8
13
- return 'sysv'
14
- else
15
- return 'systemd'
16
- end
17
- when 'ubuntu'
18
- if v[0] <= 14 && v[1] < 10
19
- return 'upstart'
20
- else
21
- return 'systemd'
22
- end
23
- when 'centos','redhat'
24
- if v[0] <= 5
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
- def init(*inits)
37
- inits = inits.flatten.map(&:to_s)
38
- actual = FPM::Fry::Plugin::Init.detect_init(variables)
39
- if inits.none?
40
- return actual
41
- elsif inits.include? actual
42
- if block_given?
43
- yield
44
- else
45
- return true
46
- end
47
- else
48
- return false
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
- def initialize(*_)
30
- super
31
- @name = nil
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
- def name( n = nil )
40
- if n
41
- @name = n
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
- def group( n = nil )
47
- if n
48
- @group = n
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
- name = self.name || builder.name || raise
84
- init = Init.detect_init(builder.variables)
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
- case(init)
88
- when 'upstart' then
89
- edit.add_file "/etc/init/#{name}.conf",StringIO.new( env.render('upstart.erb') )
90
- edit.ln_s '/lib/init/upstart-job', "/etc/init.d/#{name}"
91
- builder.plugin('script_helper') do |sh|
92
- sh.after_install_or_upgrade(<<BASH)
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
- # It has to be stop+start because upstart doesn't pickup changes with restart.
95
- if which invoke-rc.d >/dev/null 2>&1; then
96
- invoke-rc.d #{Shellwords.shellescape name} stop
97
- else
98
- stop #{Shellwords.shellescape name}
99
- fi
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
- invoke-rc.d #{Shellwords.shellescape name} start
154
+ invoke-rc.d #{Shellwords.shellescape name} start
103
155
  else
104
- start #{Shellwords.shellescape name}
156
+ start #{Shellwords.shellescape name}
105
157
  fi
106
158
  BASH
107
- sh.before_remove_entirely(<<BASH)
159
+ sh.before_remove_entirely(<<BASH)
108
160
  if status #{Shellwords.shellescape name} 2>/dev/null | grep -q ' start/'; then
109
- stop #{Shellwords.shellescape name}
161
+ stop #{Shellwords.shellescape name}
110
162
  fi
111
163
  BASH
112
- end
113
- builder.plugin('config', FPM::Fry::Plugin::Config::IMPLICIT => true) do |co|
114
- co.include "etc/init/#{name}.conf"
115
- end
116
- when 'sysv' then
117
- edit.add_file "/etc/init.d/#{name}",StringIO.new( env.render('sysv.erb') ), chmod: '750'
118
- builder.plugin('script_helper') do |sh|
119
- sh.after_install_or_upgrade(<<BASH)
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
- sh.before_remove_entirely(<<BASH)
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
- end
128
- builder.plugin('config', FPM::Fry::Plugin::Config::IMPLICIT => true) do |co|
129
- co.include "etc/init.d/#{name}"
130
- end
131
- when 'systemd' then
132
- edit.add_file "/lib/systemd/system/#{name}.service", StringIO.new( env.render('systemd.erb') ), chmod: '644'
133
- builder.plugin('script_helper') do |sh|
134
- sh.after_install_or_upgrade(<<BASH)
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
- systemctl --system daemon-reload
138
- systemctl try-reload-or-restart #{Shellwords.shellescape name}.service
197
+ systemctl --system daemon-reload
198
+ systemctl restart #{Shellwords.shellescape name}.service
139
199
  fi
140
200
  BASH
141
- sh.before_remove_entirely(<<BASH)
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