docker-stack 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +4 -0
  4. data/.rubocop.yml +25 -0
  5. data/.rubocop_todo.yml +23 -0
  6. data/.travis.yml +12 -0
  7. data/Gemfile +44 -0
  8. data/LICENSE.txt +13 -0
  9. data/README.md +117 -0
  10. data/Rakefile +12 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/docker-stack.gemspec +36 -0
  14. data/lib/docker/stack.rb +8 -0
  15. data/lib/docker/stack/container.rb +45 -0
  16. data/lib/docker/stack/controller.rb +115 -0
  17. data/lib/docker/stack/rake_task.rb +63 -0
  18. data/lib/docker/stack/version.rb +5 -0
  19. data/lib/generators/docker/stack/install_generator.rb +48 -0
  20. data/lib/generators/docker/stack/service.rb +49 -0
  21. data/lib/generators/docker/stack/service/fedora_generator.rb +20 -0
  22. data/lib/generators/docker/stack/service/postgres_generator.rb +22 -0
  23. data/lib/generators/docker/stack/service/redis_generator.rb +20 -0
  24. data/lib/generators/docker/stack/service/solr_generator.rb +22 -0
  25. data/lib/generators/docker/stack/templates/config/database.yml +23 -0
  26. data/lib/generators/docker/stack/templates/config/fedora.yml +15 -0
  27. data/lib/generators/docker/stack/templates/config/redis.yml +9 -0
  28. data/lib/generators/docker/stack/templates/config/solr.yml +7 -0
  29. data/lib/generators/docker/stack/templates/docker.rake +25 -0
  30. data/lib/generators/docker/stack/templates/services/fedora.yml.erb +9 -0
  31. data/lib/generators/docker/stack/templates/services/postgres.yml.erb +13 -0
  32. data/lib/generators/docker/stack/templates/services/redis.yml.erb +10 -0
  33. data/lib/generators/docker/stack/templates/services/solr.yml.erb +20 -0
  34. data/lib/generators/docker/stack/templates/solr/conf/_rest_managed.json +3 -0
  35. data/lib/generators/docker/stack/templates/solr/conf/admin-extra.html +31 -0
  36. data/lib/generators/docker/stack/templates/solr/conf/elevate.xml +36 -0
  37. data/lib/generators/docker/stack/templates/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  38. data/lib/generators/docker/stack/templates/solr/conf/protwords.txt +21 -0
  39. data/lib/generators/docker/stack/templates/solr/conf/schema.xml +366 -0
  40. data/lib/generators/docker/stack/templates/solr/conf/scripts.conf +24 -0
  41. data/lib/generators/docker/stack/templates/solr/conf/solrconfig.xml +322 -0
  42. data/lib/generators/docker/stack/templates/solr/conf/spellings.txt +2 -0
  43. data/lib/generators/docker/stack/templates/solr/conf/stopwords.txt +58 -0
  44. data/lib/generators/docker/stack/templates/solr/conf/stopwords_en.txt +58 -0
  45. data/lib/generators/docker/stack/templates/solr/conf/synonyms.txt +31 -0
  46. data/lib/generators/docker/stack/templates/solr/conf/xslt/example.xsl +132 -0
  47. data/lib/generators/docker/stack/templates/solr/conf/xslt/example_atom.xsl +67 -0
  48. data/lib/generators/docker/stack/templates/solr/conf/xslt/example_rss.xsl +66 -0
  49. data/lib/generators/docker/stack/templates/solr/conf/xslt/luke.xsl +337 -0
  50. data/lib/generators/docker/stack/util.rb +38 -0
  51. metadata +261 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 01f617f6f1d85078fa160cf947618cd2e124b0db6ccfba06c1bbbcc1a63d1834
4
+ data.tar.gz: 7cc64b1dbbed6174443cb16582d2ee5b2d75f9367a5a8ff15baddcb0278a8b7b
5
+ SHA512:
6
+ metadata.gz: fe00ab2abd2353f8d769ba3c7c96b9cadb39915c98578cf6db2fdb016dc48de34a44b56c00ba833a14fc379198c908f8a8438d183cbf117fe6ef1c230a72079e
7
+ data.tar.gz: c4b076f7ef25513b9c300142dc3a5f63547ca536128515ed031fd0ba03de3f14202347b9c7fa21c7bb106ff81095e163674e36fb3a6f8c213cb71bc860c2a61a
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ .internal_test_app
14
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
4
+ --order random
@@ -0,0 +1,25 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ Lint/NestedMethodDefinition:
4
+ Exclude:
5
+ - 'lib/generators/docker/stack/service.rb'
6
+ - 'lib/generators/docker/stack/util.rb'
7
+
8
+ Metrics/BlockLength:
9
+ Exclude:
10
+ - 'docker-stack.gemspec'
11
+ - 'spec/**/*'
12
+
13
+ Metrics/AbcSize:
14
+ Exclude:
15
+ - 'lib/generators/docker/stack/service.rb'
16
+ - 'lib/generators/docker/stack/util.rb'
17
+
18
+ Metrics/LineLength:
19
+ Max: 120
20
+
21
+ Metrics/MethodLength:
22
+ Max: 15
23
+ Exclude:
24
+ - 'lib/generators/docker/stack/service.rb'
25
+ - 'lib/generators/docker/stack/util.rb'
@@ -0,0 +1,23 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2018-03-20 21:56:21 -0500 using RuboCop version 0.53.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 9
10
+ Style/Documentation:
11
+ Exclude:
12
+ - 'spec/**/*'
13
+ - 'lib/docker/stack.rb'
14
+ - 'lib/docker/stack/container.rb'
15
+ - 'lib/docker/stack/controller.rb'
16
+ - 'lib/generators/docker/stack/util.rb'
17
+ - 'lib/generators/docker/stack/service.rb'
18
+ - 'lib/generators/docker/stack/install_generator.rb'
19
+ - 'lib/generators/docker/stack/service/fedora_generator.rb'
20
+ - 'lib/generators/docker/stack/service/postgres_generator.rb'
21
+ - 'lib/generators/docker/stack/service/redis_generator.rb'
22
+ - 'lib/generators/docker/stack/service/solr_generator.rb'
23
+ - 'lib/generators/docker/stack/service_generator.rb'
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+ services:
5
+ - docker
6
+ before_install:
7
+ - 'gem update --system'
8
+ - 'gem update bundler'
9
+ script:
10
+ - 'bundle exec rake ci'
11
+ rvm:
12
+ - 2.5
data/Gemfile ADDED
@@ -0,0 +1,44 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in docker-stack.gemspec
6
+ gemspec
7
+ # BEGIN ENGINE_CART BLOCK
8
+ # engine_cart: 1.2.0
9
+ # engine_cart stanza: 0.10.0
10
+ # the below comes from engine_cart, a gem used to test this Rails engine gem in the context of a Rails app.
11
+ file = File.expand_path('Gemfile', ENV['ENGINE_CART_DESTINATION'] ||
12
+ ENV['RAILS_ROOT'] || File.expand_path('.internal_test_app', __dir__))
13
+
14
+ if File.exist?(file)
15
+ begin
16
+ eval_gemfile file
17
+ rescue Bundler::GemfileError => e
18
+ Bundler.ui.warn '[EngineCart] Skipping Rails application dependencies:'
19
+ Bundler.ui.warn e.message
20
+ end
21
+ else
22
+ Bundler.ui.warn "[EngineCart] Unable to find test application dependencies in #{file}, using placeholder dependencies"
23
+
24
+ # rubocop:disable Bundler/DuplicatedGem
25
+ if ENV['RAILS_VERSION']
26
+ if ENV['RAILS_VERSION'] == 'edge'
27
+ gem 'rails', github: 'rails/rails'
28
+ ENV['ENGINE_CART_RAILS_OPTIONS'] = '--edge --skip-turbolinks'
29
+ else
30
+ gem 'rails', ENV['RAILS_VERSION']
31
+ end
32
+ end
33
+
34
+ case ENV['RAILS_VERSION']
35
+ when /^4.2/
36
+ gem 'coffee-rails', '~> 4.1.0'
37
+ gem 'responders', '~> 2.0'
38
+ gem 'sass-rails', '>= 5.0'
39
+ when /^4.[01]/
40
+ gem 'sass-rails', '< 5.0'
41
+ end
42
+ # rubocop:enable Bundler/DuplicatedGem
43
+ end
44
+ # END ENGINE_CART BLOCK
@@ -0,0 +1,13 @@
1
+ Copyright 2018 Michael B. Klein
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,117 @@
1
+ # Docker::Stack
2
+
3
+ Rails generators, Rake tasks, and support modules to run dependencies in Docker containers.
4
+
5
+ Code: [![Version](https://badge.fury.io/rb/docker-stack.png)](http://badge.fury.io/rb/docker-stack)
6
+ [![Build Status](https://travis-ci.org/mbklein/docker-stack.png?branch=master)](https://travis-ci.org/mbklein/docker-stack)
7
+ [![Coverage Status](https://coveralls.io/repos/github/mbklein/docker-stack/badge.svg?branch=master)](https://coveralls.io/github/mbklein/docker-stack?branch=master)
8
+ [![Code Climate](https://codeclimate.com/github/mbklein/docker-stack/badges/gpa.svg)](https://codeclimate.com/github/mbklein/docker-stack)
9
+ [![Dependency Update Status](https://gemnasium.com/mbklein/docker-stack.png)](https://gemnasium.com/mbklein/docker-stack)
10
+ [![Dependency Maintenance Status](https://dependencyci.com/github/mbklein/docker-stack/badge)](https://dependencyci.com/github/mbklein/docker-stack)
11
+
12
+ Docs: [![Documentation Status](https://inch-ci.org/github/mbklein/docker-stack.svg?branch=master)](https://inch-ci.org/github/mbklein/docker-stack)
13
+ [![API Docs](http://img.shields.io/badge/API-docs-blue.svg)](http://rubydoc.info/gems/docker-stack)
14
+ [![Apache 2.0 License](http://img.shields.io/badge/APACHE2-license-blue.svg)](./LICENSE.txt)
15
+
16
+ Originally written as a drop-in replacement for [`solr_wrapper`](https://github.com/cbeer/solr_wrapper) and [`fcrepo_wrapper`](https://github.com/cbeer/fcrepo_wrapper) to ease development and testing of [Samvera](https://github.com/mbklein/) applications, but with an eye toward adding support for additional services.
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'docker-stack'
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install docker-stack
33
+
34
+ ## Usage
35
+
36
+ ### Initial Setup
37
+
38
+ From your application root, run:
39
+
40
+ $ rails generate docker:stack:install
41
+
42
+ This creates the Docker configuration files for the development and test environments, and adds `lib/tasks/docker.rake` to provide the Docker-related rake tasks to your application.
43
+
44
+ Then run the service generator for each support service your application needs:
45
+
46
+ $ rails generate docker:stack:service:fedora
47
+ $ rails generate docker:stack:service:solr
48
+
49
+ This will create the Docker service definitions for Fedora and Solr and drop the appropriate configuration files to point to them in the `config` directory. The Solr generator also creates a `solr` directory containing default core configuration files.
50
+
51
+ To do all of the above with one command, you can run:
52
+
53
+ $ rails generate docker:stack:install --services fedora,solr
54
+
55
+ ### Controlling the Stack
56
+
57
+ `Docker::Stack` defines a bunch of rake tasks to control the Docker services (and sometimes do other things). These are defined in your application in `lib/tasks/docker.rake`, and can be customized according to your application's needs. The following descriptions apply to the default tasks installed by the `docker:stack:install` generator.
58
+
59
+ #### Environment-Specific Tasks
60
+
61
+ Every `docker:dev` task is also available as a `docker:test` task. The gem forwards different ports to the host in development and test modes, so both stacks can be running at once. The only difference between the two is that the test stack cleans up after itself automatically when it terminates, while the development stack keeps its data around.
62
+
63
+ ##### Spin up the stack in the foreground
64
+
65
+ $ rake docker:dev:up
66
+
67
+ The required Docker machine images will be downloaded and registered the first time you run this command. Subsequent runs will be much faster.
68
+
69
+ ##### Spin up the stack in the background
70
+
71
+ $ rake docker:dev:daemon
72
+
73
+ ##### Terminate running services
74
+
75
+ Even if they're running in the foreground in another tab!
76
+
77
+ $ rake docker:dev:down
78
+
79
+ ##### Display the status of all running services
80
+
81
+ $ rake docker:dev:status
82
+
83
+ ##### Clean up all persistent data
84
+
85
+ $ rake docker:dev:clean
86
+
87
+ ##### Display container logs
88
+
89
+ $ rake docker:dev:logs
90
+
91
+ Similar to `tail -f` on a file.
92
+ Add a `SERVICES` variable to display only specific services' logs (e.g., `rake docker:dev:logs SERVICES=fedora`)
93
+
94
+ ##### Reset the entire stack
95
+
96
+ $ rake docker:dev:reset
97
+
98
+ AKA "The Nuclear Option." Removes all containers, data, and machine images associated with this stack. This will result in Docker images being re-downloaded and initialized the next time you spin things up.
99
+
100
+ #### Convenience Tasks
101
+
102
+ ##### Run application tests under the test stack
103
+
104
+ $ rake docker:spec
105
+
106
+ 1. Spins up the test environment
107
+ 2. Invokes the `db:setup` task
108
+ 3. Invokes the first task it finds named `spec` or `rspec` or matching the value of the `SPEC_TASK` environment variable
109
+ 4. Terminates and cleans up the test environment
110
+
111
+ ## Contributing
112
+
113
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mbklein/docker-stack.
114
+
115
+ ## License
116
+
117
+ The gem is available as open source under the terms of the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'engine_cart/rake_task'
3
+ require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ RuboCop::RakeTask.new
8
+
9
+ task default: :ci
10
+
11
+ task ci: ['rubocop', 'engine_cart:clean', 'engine_cart:generate', 'spec'] do
12
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'docker/stack'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,36 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'docker/stack/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'docker-stack'
7
+ spec.version = Docker::Stack::VERSION
8
+ spec.authors = ['Michael Klein']
9
+ spec.email = ['mbklein@gmail.com']
10
+
11
+ spec.summary = 'Support code and rake tasks for running Rails on top of Dockerized services.'
12
+ spec.description = 'Support code and rake tasks for running Rails on top of Dockerized services.'
13
+ spec.homepage = 'https://github.com/mbklein/docker-stack'
14
+ spec.license = 'Apache2'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_dependency 'docker-api'
24
+ spec.add_dependency 'docker-compose'
25
+ spec.add_dependency 'rails', ['~> 5.0']
26
+
27
+ spec.add_development_dependency 'bixby'
28
+ spec.add_development_dependency 'bundler', '~> 1.16'
29
+ spec.add_development_dependency 'byebug'
30
+ spec.add_development_dependency 'engine_cart'
31
+ spec.add_development_dependency 'mocha'
32
+ spec.add_development_dependency 'pry-byebug'
33
+ spec.add_development_dependency 'rake', '~> 12.0'
34
+ spec.add_development_dependency 'rspec', '~> 3.0'
35
+ spec.add_development_dependency 'rubocop'
36
+ end
@@ -0,0 +1,8 @@
1
+ require 'docker/stack/container'
2
+ require 'docker/stack/controller'
3
+ require 'docker/stack/version'
4
+
5
+ module Docker
6
+ module Stack
7
+ end
8
+ end
@@ -0,0 +1,45 @@
1
+ require 'action_view'
2
+
3
+ module Docker
4
+ module Stack
5
+ class Container
6
+ include ::ActionView::Helpers::DateHelper
7
+
8
+ def initialize(id)
9
+ @id = id
10
+ @container = Docker::Container.get(id)
11
+ end
12
+
13
+ def service
14
+ info('Config', 'Labels', 'com.docker.compose.service')
15
+ end
16
+
17
+ def status
18
+ info('State', 'Health', 'Status')
19
+ end
20
+
21
+ def started
22
+ value = info('State', 'StartedAt')
23
+ return value if value == 'unknown'
24
+ Time.parse(value).utc
25
+ end
26
+
27
+ def uptime_in_words
28
+ return started if started == 'unknown'
29
+ time_ago_in_words(started)
30
+ end
31
+
32
+ def to_h
33
+ { id: @id, service: service, status: status, started: started, running: uptime_in_words }
34
+ end
35
+
36
+ private
37
+
38
+ def info(*keys)
39
+ result = @container.info
40
+ keys.each { |key| result = result[key] }
41
+ result
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,115 @@
1
+ require 'docker/compose'
2
+ require 'docker-api'
3
+
4
+ module Docker
5
+ module Stack
6
+ class Controller
7
+ attr_reader :dc, :cleanup, :daemon
8
+
9
+ def self.default_project_name
10
+ Rails.application.class.parent_name.underscore
11
+ end
12
+
13
+ def initialize(project: self.class.default_project_name, env: nil, cleanup: false, daemon: false)
14
+ env = Rails.env if env.nil?
15
+ project_and_env = [project, env].join('-')
16
+ @workdir = Rails.root.join('.docker-stack', project_and_env)
17
+ @dc = ::Docker::Compose::Session.new(dir: @workdir)
18
+ @cleanup = cleanup
19
+ @daemon = daemon
20
+ end
21
+
22
+ def reset!
23
+ down(cleanup: true)
24
+ images = config['services'].values.map { |conf| conf['image'] }
25
+ images.each do |image_name|
26
+ begin
27
+ image = ::Docker::Image.get(image_name)
28
+ result = image.remove(prune: true)
29
+ yield result if block_given?
30
+ rescue ::Docker::Error::NotFoundError
31
+ yield %{[{"Skipped":"#{image_name} (image not present)"}]}
32
+ end
33
+ end
34
+ ::Docker::Image.prune
35
+ end
36
+
37
+ def status
38
+ containers = dc.ps.map(&:id)
39
+ containers.map do |c|
40
+ begin
41
+ container = Container.new(c)
42
+ container.to_h
43
+ rescue StandardError
44
+ { id: c, service: 'unknown', status: 'unknown', started: 'unknown', running: 'unknown' }
45
+ end
46
+ end
47
+ end
48
+
49
+ # rubocop:disable Style/StderrPuts
50
+ def wait_for_services
51
+ Timeout.timeout(120) do
52
+ $stderr.print 'Waiting up to two minutes for services to become healthy.' if warn?
53
+ loop do
54
+ break if status.all? { |v| v[:status] == 'healthy' }
55
+ $stderr.print '.' if warn?
56
+ sleep 2
57
+ end
58
+ $stderr.puts if warn?
59
+ end
60
+ true
61
+ rescue Timeout::Error
62
+ raise 'Timed out waiting for services to become healthy'
63
+ end
64
+ # rubocop:enable Style/StderrPuts
65
+
66
+ def run
67
+ dc.up(detached: @daemon || block_given?)
68
+ return true unless block_given?
69
+
70
+ begin
71
+ wait_for_services
72
+ yield
73
+ ensure
74
+ down
75
+ end
76
+ end
77
+
78
+ def logs(*services)
79
+ trap_int(terminate: false) { dc.run!('logs', '-f', services) }
80
+ end
81
+
82
+ def start(&block)
83
+ trap_int { run(&block) }
84
+ end
85
+
86
+ def with_containers(&block)
87
+ trap_int { run(&block) }
88
+ end
89
+
90
+ def down(cleanup: @cleanup)
91
+ dc.run!('down', v: cleanup)
92
+ end
93
+
94
+ private
95
+
96
+ def config
97
+ @config ||= YAML.safe_load(File.read(File.join(dc.dir, dc.file)))
98
+ end
99
+
100
+ def trap_int(terminate: true)
101
+ old_trap = Signal.trap('INT') do
102
+ down if terminate
103
+ raise SystemExit
104
+ end
105
+ yield
106
+ ensure
107
+ Signal.trap('INT', old_trap)
108
+ end
109
+
110
+ def warn?
111
+ $-W > 0 # rubocop:disable Style/GlobalVars
112
+ end
113
+ end
114
+ end
115
+ end