dapp 0.0.24 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +13 -5
  2. data/bin/dapp +17 -1
  3. data/config/en/common.yml +23 -0
  4. data/config/en/net_status.yml +24 -0
  5. data/lib/dapp.rb +68 -12
  6. data/lib/dapp/application.rb +57 -0
  7. data/lib/dapp/application/git_artifact.rb +26 -0
  8. data/lib/dapp/application/logging.rb +120 -0
  9. data/lib/dapp/application/path.rb +31 -0
  10. data/lib/dapp/application/tags.rb +65 -0
  11. data/lib/dapp/build/stage/app_install.rb +19 -0
  12. data/lib/dapp/build/stage/app_setup.rb +19 -0
  13. data/lib/dapp/build/stage/base.rb +106 -0
  14. data/lib/dapp/build/stage/from.rb +40 -0
  15. data/lib/dapp/build/stage/infra_install.rb +23 -0
  16. data/lib/dapp/build/stage/infra_setup.rb +19 -0
  17. data/lib/dapp/build/stage/source_1.rb +31 -0
  18. data/lib/dapp/build/stage/source_1_archive.rb +31 -0
  19. data/lib/dapp/build/stage/source_2.rb +20 -0
  20. data/lib/dapp/build/stage/source_3.rb +27 -0
  21. data/lib/dapp/build/stage/source_4.rb +31 -0
  22. data/lib/dapp/build/stage/source_5.rb +51 -0
  23. data/lib/dapp/build/stage/source_base.rb +109 -0
  24. data/lib/dapp/builder/base.rb +44 -0
  25. data/lib/dapp/builder/chef.rb +242 -0
  26. data/lib/dapp/builder/chef/berksfile.rb +54 -0
  27. data/lib/dapp/builder/shell.rb +16 -0
  28. data/lib/dapp/cli.rb +10 -44
  29. data/lib/dapp/cli/base.rb +55 -0
  30. data/lib/dapp/cli/build.rb +6 -140
  31. data/lib/dapp/cli/flush.rb +19 -0
  32. data/lib/dapp/cli/flush/build_cache.rb +26 -0
  33. data/lib/dapp/cli/flush/stage_cache.rb +23 -0
  34. data/lib/dapp/cli/list.rb +19 -0
  35. data/lib/dapp/cli/push.rb +59 -0
  36. data/lib/dapp/cli/smartpush.rb +19 -0
  37. data/lib/dapp/config/application.rb +98 -0
  38. data/lib/dapp/config/chef.rb +20 -0
  39. data/lib/dapp/config/docker.rb +39 -0
  40. data/lib/dapp/config/git_artifact.rb +78 -0
  41. data/lib/dapp/config/main.rb +23 -0
  42. data/lib/dapp/config/shell.rb +40 -0
  43. data/lib/dapp/controller.rb +103 -0
  44. data/lib/dapp/docker_image.rb +51 -0
  45. data/lib/dapp/error/application.rb +6 -0
  46. data/lib/dapp/error/base.rb +10 -0
  47. data/lib/dapp/error/build.rb +6 -0
  48. data/lib/dapp/error/config.rb +6 -0
  49. data/lib/dapp/error/controller.rb +6 -0
  50. data/lib/dapp/error/shellout.rb +6 -0
  51. data/lib/dapp/filelock.rb +1 -1
  52. data/lib/dapp/git_artifact.rb +43 -272
  53. data/lib/dapp/git_repo/base.rb +10 -12
  54. data/lib/dapp/git_repo/own.rb +7 -3
  55. data/lib/dapp/git_repo/remote.rb +14 -20
  56. data/lib/dapp/helper/cli.rb +66 -0
  57. data/lib/dapp/helper/i18n.rb +20 -0
  58. data/lib/dapp/helper/log.rb +72 -0
  59. data/lib/dapp/helper/paint.rb +27 -0
  60. data/lib/dapp/helper/sha256.rb +14 -0
  61. data/lib/dapp/helper/shellout.rb +41 -0
  62. data/lib/dapp/helper/streaming.rb +49 -0
  63. data/lib/dapp/helper/trivia.rb +27 -0
  64. data/lib/dapp/stage_image.rb +98 -0
  65. data/lib/dapp/version.rb +3 -1
  66. metadata +207 -51
  67. data/lib/dapp/atomizer.rb +0 -56
  68. data/lib/dapp/builder.rb +0 -230
  69. data/lib/dapp/builder/cascade_tagging.rb +0 -48
  70. data/lib/dapp/builder/centos7.rb +0 -47
  71. data/lib/dapp/builder/chefify.rb +0 -107
  72. data/lib/dapp/builder/ci_tagging.rb +0 -53
  73. data/lib/dapp/builder/git_tagging.rb +0 -21
  74. data/lib/dapp/builder/manual_tagging.rb +0 -22
  75. data/lib/dapp/builder/ubuntu1404.rb +0 -20
  76. data/lib/dapp/builder/ubuntu1604.rb +0 -20
  77. data/lib/dapp/docker.rb +0 -207
  78. data/lib/dapp/git_repo/chronicler.rb +0 -44
data/lib/dapp/atomizer.rb DELETED
@@ -1,56 +0,0 @@
1
- module Dapp
2
- # "Transaction" journal with rollback (mainly to protect cache fill with unbuildable configuration)
3
- class Atomizer
4
- def initialize(builder, file_path, lock_timeout: 10)
5
- @builder = builder
6
- @file_path = file_path
7
- @lock_timeout = lock_timeout
8
- @file = open
9
-
10
- builder.register_atomizer self
11
- end
12
-
13
- def <<(path)
14
- file.puts path
15
- file.fsync
16
- end
17
-
18
- def commit!
19
- @file.truncate(0)
20
- @file.close
21
- @file = open
22
- end
23
-
24
- protected
25
-
26
- attr_reader :file_path
27
- attr_reader :builder
28
-
29
- attr_reader :lock_timeout
30
- attr_reader :file
31
-
32
- def open
33
- file = File.open(file_path, File::RDWR | File::CREAT, 0644)
34
-
35
- file.sync = true
36
-
37
- Timeout.timeout(lock_timeout) do
38
- file.flock(File::LOCK_EX)
39
- end
40
-
41
- if (not_commited_paths = file.read.lines.map(&:strip))
42
- FileUtils.rm_rf not_commited_paths
43
- end
44
-
45
- file.truncate(0)
46
- file.rewind
47
-
48
- file
49
- rescue Timeout::Error
50
- file.close
51
-
52
- STDERR.puts 'Atomizer already in use! Try again later.'
53
- exit 1
54
- end
55
- end
56
- end
data/lib/dapp/builder.rb DELETED
@@ -1,230 +0,0 @@
1
- module Dapp
2
- # Main class that does all stuff
3
- class Builder
4
- include Chefify
5
- include Centos7
6
- include Ubuntu1404
7
- include Ubuntu1604
8
- include CiTagging
9
- include ManualTagging
10
- include GitTagging
11
- include CascadeTagging
12
- include Filelock
13
-
14
- class << self
15
- def default_opts
16
- @default_opts ||= {}
17
- end
18
-
19
- def dappfiles_paths(path, pattern = '*')
20
- pattern.split('-').instance_eval { count.downto(1).map { |n| slice(0, n).join('-') } }
21
- .map { |p| Dir.glob(File.join([path, p, default_opts[:dappfile_name] || 'Dappfile'].compact)) }.find(&:any?) || []
22
- end
23
-
24
- def process_directory(path, pattern = '*')
25
- dappfiles_paths(path, pattern).map { |dappfile_path| process_file(dappfile_path, app_filter: pattern).builded_apps }.flatten
26
- end
27
-
28
- def process_file(dappfile_path, app_filter: '*')
29
- new(dappfile_path: dappfile_path, app_filter: app_filter) do |builder|
30
- builder.log "Processing application #{builder.name} (#{dappfile_path})"
31
-
32
- # indent all subsequent messages
33
- builder.indent_log
34
-
35
- # eval instructions from file
36
- builder.instance_eval File.read(dappfile_path), dappfile_path
37
-
38
- # commit atomizers
39
- builder.commit_atomizers!
40
- end
41
- end
42
- end
43
-
44
- def log(message)
45
- puts ' ' * opts[:log_indent] + ' * ' + message if opts[:log_verbose] || !opts[:log_quiet]
46
- end
47
-
48
- def shellout(*args, log_verbose: false, **kwargs)
49
- kwargs[:live_stream] = STDOUT if log_verbose && opts[:log_verbose]
50
- Mixlib::ShellOut.new(*args, :timeout => 3600, **kwargs).run_command.tap(&:error!)
51
- end
52
-
53
- def home_path(*path)
54
- path.compact.inject(Pathname.new(opts[:home_path]), &:+).expand_path.to_s
55
- end
56
-
57
- def build_path(*path)
58
- path.compact.inject(Pathname.new(opts[:build_path]), &:+).expand_path.tap do |p|
59
- FileUtils.mkdir_p p.parent
60
- end.to_s
61
- end
62
-
63
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
64
- def initialize(**options)
65
- opts.merge! self.class.default_opts
66
- opts.merge! options
67
-
68
- # default log indentation
69
- opts[:log_indent] = 0
70
-
71
- # basename
72
- if opts[:name]
73
- opts[:basename] = opts[:name]
74
- opts[:name] = nil
75
- elsif opts[:dappfile_path]
76
- opts[:basename] ||= Pathname.new(opts[:dappfile_path]).expand_path.parent.basename
77
- end
78
-
79
- # home path
80
- opts[:home_path] ||= Pathname.new(opts[:dappfile_path] || 'fakedir').parent.expand_path.to_s
81
-
82
- # build path
83
- opts[:build_path] = opts[:build_dir] ? opts[:build_dir] : home_path('build')
84
- opts[:build_path] = build_path opts[:basename] if opts[:shared_build_dir]
85
-
86
- # home branch
87
- @home_branch = shellout("git -C #{home_path} rev-parse --abbrev-ref HEAD").stdout.strip
88
-
89
- # atomizers
90
- @atomizers = []
91
-
92
- # account builded apps
93
- @builded_apps = []
94
-
95
- lock do
96
- yield self
97
- end
98
- end
99
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
100
-
101
- def indent_log
102
- opts[:log_indent] += 1
103
- end
104
-
105
- attr_reader :home_branch
106
-
107
- def builded_apps
108
- @builded_apps.dup
109
- end
110
-
111
- def docker
112
- docker_stack.last
113
- end
114
-
115
- def scope(&blk)
116
- stack_settings(&blk)
117
- end
118
-
119
- def app(name)
120
- log "Processing #{self.name}-#{name}"
121
-
122
- name = "#{opts[:name]}-#{name}" if opts[:name]
123
-
124
- stack_settings name: name, log_indent: opts[:log_indent] + 1 do
125
- docker.name name
126
-
127
- yield
128
- end
129
- end
130
-
131
- def name
132
- [opts[:basename], opts[:name]].compact.join '-'
133
- end
134
-
135
- def add_git_artifact(where_to_add, **kwargs)
136
- log "Adding artifact (to #{where_to_add})"
137
-
138
- # own repo
139
- repo = GitRepo::Own.new(self)
140
-
141
- # add artifact
142
- artifact = GitArtifact.new(self, repo, where_to_add, flush_cache: opts[:flush_cache], branch: home_branch, **kwargs)
143
- artifact.add_multilayer!
144
- end
145
-
146
- def add_remote_git_artifact(url, where_to_add, branch: opts[:git_artifact_branch] || home_branch, ssh_key_path: nil, **kwargs)
147
- log "Adding artifact from git (#{url} to #{where_to_add}, branch: #{branch})"
148
-
149
- # extract git repo name from url
150
- repo_name = url.gsub(%r{.*?([^\/ ]+)\.git}, '\\1')
151
-
152
- # clone or fetch
153
- repo = GitRepo::Remote.new(self, repo_name, url: url, ssh_key_path: ssh_key_path)
154
- repo.fetch!(branch)
155
-
156
- # add artifact
157
- artifact = GitArtifact.new(self, repo, where_to_add, flush_cache: opts[:flush_cache], branch: branch, **kwargs)
158
- artifact.add_multilayer!
159
- end
160
-
161
- # rubocop:disable Metrics/AbcSize
162
- def build(**_kwargs)
163
- # check app name
164
- unless !opts[:app_filter] || File.fnmatch("#{opts[:app_filter]}*", name)
165
- log "Skipped (does not match filter: #{opts[:app_filter]})!"
166
- return false
167
- end
168
-
169
- # build image
170
- log 'Building'
171
- image_id = docker.build
172
-
173
- # apply tagging
174
- %w(ci manual git cascade).each do |strategy|
175
- send "tag_#{strategy}", image_id
176
- end
177
-
178
- # push to repo
179
- if opts[:docker_repo]
180
- log 'Pushing to docker repo'
181
- docker.push name: name, repo: opts[:docker_repo]
182
- end
183
-
184
- # count it
185
- @builded_apps << name
186
-
187
- image_id
188
- end
189
- # rubocop:enable Metrics/AbcSize
190
-
191
- def register_atomizer(atomizer)
192
- atomizers << atomizer
193
- end
194
-
195
- def commit_atomizers!
196
- atomizers.each(&:commit!)
197
- end
198
-
199
- protected
200
-
201
- attr_reader :atomizers
202
-
203
- def opts
204
- opts_stack.last
205
- end
206
-
207
- def opts_stack
208
- @opts_stack ||= [{}]
209
- end
210
-
211
- def docker_stack
212
- @docker_stack ||= [Docker.new(self)]
213
- end
214
-
215
- def stack_settings(**options)
216
- opts_stack.push opts.merge(options).dup
217
- docker_stack.push docker.dup
218
-
219
- yield
220
- ensure
221
- docker_stack.pop
222
- opts_stack.pop
223
- end
224
-
225
- def lock(**kwargs, &block)
226
- filelock(build_path("#{home_branch}.lock"), error_message: "Application #{opts[:basename]} (#{home_branch}) in use! Try again later.", **kwargs,
227
- &block)
228
- end
229
- end
230
- end
@@ -1,48 +0,0 @@
1
- module Dapp
2
- class Builder
3
- # Cascade tagging strategy
4
- module CascadeTagging
5
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
6
- def tag_cascade(image_id)
7
- return unless opts[:tag_cascade]
8
-
9
- log 'Applying cascade tagging'
10
-
11
- opts[:build_history_length] ||= 10
12
-
13
- spec = {
14
- name: name,
15
- tag: home_branch,
16
- repo: opts[:docker_repo]
17
- }
18
-
19
- # return if nothing changed
20
- return if image_id == docker.image_id(spec)
21
-
22
- # remove excess tags
23
- tags_to_remove = docker.images(name: spec[:name], repo: spec[:repo])
24
- tags_to_remove.map! { |image| image[:tag] }
25
- tags_to_remove.select! { |tag| tag.start_with?("#{spec[:tag]}_") && tag.sub(/^#{spec[:tag]}_/, '').to_i >= opts[:build_history_length] }
26
- tags_to_remove.each do |tag_to_remove|
27
- docker.rmi spec.merge(tag: tag_to_remove)
28
- end
29
-
30
- # shift old images: 1 -> 2, 2 -> 3, ..., n -> n+1
31
- (opts[:build_history_length] - 1).downto(1).each do |n|
32
- origin = spec.merge(tag: "#{spec[:tag]}_#{n}")
33
-
34
- if docker.image_exist?(**origin)
35
- docker.tag origin, spec.merge(tag: "#{spec[:tag]}_#{n + 1}")
36
- end
37
- end
38
-
39
- # shift top -> 1
40
- docker.tag spec, spec.merge(tag: "#{spec[:tag]}_1") if docker.image_exist?(**spec)
41
-
42
- # tag top
43
- docker.tag image_id, spec
44
- end
45
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
46
- end
47
- end
48
- end
@@ -1,47 +0,0 @@
1
- module Dapp
2
- class Builder
3
- # Centos7 support
4
- module Centos7
5
- # rubocop:disable Metrics/MethodLength
6
- def from_centos7
7
- # use centos7
8
- docker.from 'centos:7'
9
-
10
- # add real systemd
11
- docker.env container: 'docker', step: :begining
12
- docker.run(
13
- 'yum -y update; yum clean all',
14
- '(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done)',
15
- 'rm -f /lib/systemd/system/multi-user.target.wants/*',
16
- 'rm -f /etc/systemd/system/*.wants/*',
17
- 'rm -f /lib/systemd/system/local-fs.target.wants/*',
18
- 'rm -f /lib/systemd/system/sockets.target.wants/*udev*',
19
- 'rm -f /lib/systemd/system/sockets.target.wants/*initctl*',
20
- 'rm -f /lib/systemd/system/basic.target.wants/*',
21
- 'rm -f /lib/systemd/system/anaconda.target.wants/*',
22
- 'rm -f /lib/systemd/system/systemd-remount-fs.service',
23
- 'rm -f /lib/systemd/system/sys-fs-fuse-connections.mount',
24
- step: :begining
25
- )
26
- docker.volume '/sys/fs/cgroup', step: :begining
27
- docker.cmd '/usr/sbin/init', step: :begining
28
-
29
- # cache yum fastestmirror
30
- docker.run 'yum makecache', step: :begining
31
-
32
- # TERM & utf8
33
- docker.run 'localedef -c -f UTF-8 -i en_US en_US.UTF-8', step: :begining
34
- docker.env TERM: 'xterm', LANG: 'en_US.UTF-8', LANGUAGE: 'en_US:en', LC_ALL: 'en_US.UTF-8', step: :begining
35
-
36
- # centos hacks
37
- docker.run(
38
- 'sed \'s/\(-\?session\s\+optional\s\+pam_systemd\.so.*\)/#\1/g\' -i /etc/pam.d/system-auth',
39
- 'yum install -y sudo git',
40
- 'echo \'Defaults:root !requiretty\' >> /etc/sudoers',
41
- step: :begining
42
- )
43
- end
44
- # rubocop:enable Metrics/MethodLength
45
- end
46
- end
47
- end
@@ -1,107 +0,0 @@
1
- module Dapp
2
- class Builder
3
- # Build using chef "dapp" cookbooks
4
- module Chefify
5
- def dappit(*extra_dapps, chef_version: '12.5.1', **_kwargs)
6
- log 'Adding dapp chef cookbook artifact and chef solo run'
7
-
8
- setup_dapp_chef chef_version
9
-
10
- # run chef solo
11
- [:prepare, :build, :setup].each do |step|
12
- # run chef-solo for extra dapps
13
- extra_dapps.each do |extra_dapp|
14
- if dapp_chef_cookbooks_artifact.exist_in_step? "cookbooks/mdapp-#{extra_dapp}/recipes/#{step}.rb", step
15
- docker.run "chef-solo -c /usr/share/dapp/chef_solo.rb -o mdapp-#{extra_dapp}::#{step},dapp-#{opts[:basename]}::void", step: step
16
- end
17
- end
18
-
19
- # run chef-solo for app
20
- recipe = [opts[:name], step].compact.join '-'
21
- if dapp_chef_cookbooks_artifact.exist_in_step? "cookbooks/dapp-#{opts[:basename]}/recipes/#{recipe}.rb", step
22
- docker.run "chef-solo -c /usr/share/dapp/chef_solo.rb -o dapp-#{opts[:basename]}::#{recipe}", step: step
23
- end
24
- end
25
- end
26
-
27
- def build_dapp(*args, extra_dapps: [], **kwargs, &blk)
28
- stack_settings do
29
- dappit(*extra_dapps, **kwargs)
30
-
31
- build(*args, **kwargs, &blk)
32
- end
33
- end
34
-
35
- protected
36
-
37
- def dapp_chef_cookbooks_artifact
38
- unless @dapp_chef_cookbooks_artifact
39
- # init cronicler
40
- repo = GitRepo::Chronicler.new(self, 'dapp_cookbooks', build_path: home_branch)
41
-
42
- # warmup berks cache
43
- Dir.mktmpdir('dapp_berks_warmup') do |tmpdir_path|
44
- FileUtils.cp home_path('Berksfile'), tmpdir_path
45
- FileUtils.cp home_path('metadata.rb'), tmpdir_path
46
- shellout 'berks install', cwd: tmpdir_path
47
- end
48
-
49
- # verify berks lock
50
- shellout "berks verify --berksfile=#{home_path 'Berksfile'}"
51
-
52
- # vendor cookbooks
53
- shellout "berks vendor --berksfile=#{home_path 'Berksfile'} #{repo.chronodir_path 'cookbooks'}", log_verbose: true
54
-
55
- # create void receipt
56
- FileUtils.touch repo.chronodir_path 'cookbooks', "dapp-#{opts[:basename]}", 'recipes', 'void.rb'
57
-
58
- # commit (if smth changed)
59
- repo.commit!
60
-
61
- # init artifact
62
- @dapp_chef_cookbooks_artifact = GitArtifact.new(self, repo, '/usr/share/dapp/chef_repo/cookbooks',
63
- cwd: 'cookbooks', build_path: home_branch, flush_cache: opts[:flush_cache])
64
- end
65
-
66
- @dapp_chef_cookbooks_artifact
67
- end
68
-
69
- def install_chef_and_setup_chef_solo(chef_version)
70
- docker.run(
71
- "curl -L https://www.opscode.com/chef/install.sh | bash -s -- -v #{chef_version}",
72
- 'mkdir -p /usr/share/dapp/chef_repo /var/cache/dapp/chef',
73
- 'echo file_cache_path \\"/var/cache/dapp/chef\\" > /usr/share/dapp/chef_solo.rb',
74
- 'echo cookbook_path \\"/usr/share/dapp/chef_repo/cookbooks\\" >> /usr/share/dapp/chef_solo.rb',
75
- step: :begining
76
- )
77
- end
78
-
79
- def run_chef_solo_for_mdapp_common
80
- [:prepare, :build, :setup].each do |step|
81
- if dapp_chef_cookbooks_artifact.exist_in_step? "cookbooks/mdapp-common/recipes/#{step}.rb", step
82
- docker.run "chef-solo -c /usr/share/dapp/chef_solo.rb -o mdapp-common::#{step},dapp-#{opts[:basename]}::void", step: step
83
- end
84
- end
85
- end
86
-
87
- def setup_dapp_chef(chef_version)
88
- if opts[:dapp_chef_version]
89
- raise "dapp chef version mismatch, version #{opts[:dapp_chef_version]} already installed" if opts[:dapp_chef_version] != chef_version
90
- return
91
- end
92
-
93
- # install chef, setup chef_solo
94
- install_chef_and_setup_chef_solo(chef_version)
95
-
96
- # add cookbooks
97
- dapp_chef_cookbooks_artifact.add_multilayer!
98
-
99
- # mark chef as installed
100
- opts[:dapp_chef_version] = chef_version
101
-
102
- # run chef solo for mdapp-common
103
- run_chef_solo_for_mdapp_common
104
- end
105
- end
106
- end
107
- end