concourse-technician 0.3.4 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e124b3ec79ff6952ad28547f53e6ab42271d509a
4
- data.tar.gz: 2a816dbb8ee2c1ec2cc32b7ec095c019af487994
3
+ metadata.gz: 4c97c608157d2c56434e208f79d548d58fd591c7
4
+ data.tar.gz: 5717fe2194475f37fa01e47ff57d0c9af67eefbb
5
5
  SHA512:
6
- metadata.gz: 9967df2118470c437ceb6c788b2fc9f8c7eabffd03577d4db874f8bd43d0999bdc40733a156dd1591a79532cf85072d4c044717f2588c1492590153c1d3f70f9
7
- data.tar.gz: deea7e620f9b8fba9b213397fbe7d951c38aef8aa4c0d1f58268825aada852d05fb3632319f83e5e2654d67766f57c9953f0ffc401fc85ef783e1b3008377460
6
+ metadata.gz: 194f576c50f1459eb1b1a48b5387f9281256e8efee93877c928e7fd684202a7cdcc325aaed2a16091d298c65440d530f857ebc6fca08df446c5d8cca31a67dce
7
+ data.tar.gz: 94af80ccab86ad6dc1dd36b941453f086aa86c518f00e9bc75d8c03b7f670e807e94204f54fab295438c564c8a67b293a8cb9ac11f3ae007f494f50e31c8019e
data/README.org CHANGED
@@ -11,23 +11,56 @@
11
11
  gem install concourse-technician
12
12
  #+END_SRC
13
13
 
14
+ * Configuration
15
+
16
+ ~concourse-technician~ needs to be pointed at your Concourse database. It
17
+ looks for a configuration file at =~/.config/concourse-technician.yaml=. To
18
+ tell it to look somewhere else, set =CONCOURSE_TECHNICIAN_CONFIG= in the
19
+ environment.
20
+
21
+ ** Example
22
+
23
+ #+BEGIN_SRC yaml
24
+ ---
25
+ adapter: postgres
26
+ database: my-awesome-database
27
+ host: localhost
28
+ password: MyVerySecurePasswordStoredUnencryptedOnDisk
29
+ port: 5432
30
+ user: me
31
+
32
+ volumes_root: /concourse/volumes
33
+ #+END_SRC
34
+
14
35
  * Usage
15
36
 
16
37
  To get a list of abandoned volumes...
17
38
 
18
39
  #+BEGIN_SRC shell
19
- technician abandoned_volumes
40
+ technician database abandoned_volumes
20
41
  #+END_SRC
21
42
 
22
43
  To clean up all abandoned volumes...
23
44
 
24
45
  #+BEGIN_SRC shell
25
- technician delete_abandoned_volumes
46
+ technician database delete_abandoned_volumes
47
+ #+END_SRC
48
+
49
+ To check if a worker is failing due to issues with volume reaping...
50
+
51
+ #+BEGIN_SRC shell
52
+ technician volume_reaper damaged
53
+ #+END_SRC
54
+
55
+ To resolve issues with volume reaping...
56
+
57
+ #+BEGIN_SRC shell
58
+ technician volume_reaper repair
26
59
  #+END_SRC
27
60
 
28
61
  * License
29
62
 
30
- ~dbviz~ is available under the [[https://tldrlegal.com/license/mit-license][MIT License]]. See ~LICENSE.txt~ for the full text.
63
+ ~concourse-technician~ is available under the [[https://tldrlegal.com/license/mit-license][MIT License]]. See ~LICENSE.txt~ for the full text.
31
64
 
32
65
  * Contributors
33
66
 
data/bin/technician CHANGED
@@ -3,9 +3,13 @@
3
3
  require 'json'
4
4
  require 'concourse-technician/cli'
5
5
  require 'concourse-technician/database'
6
+ require 'concourse-technician/volume_reaper'
6
7
 
7
- ConcourseTechnician::Database.new.tap do |database|
8
- ConcourseTechnician::CLI.new(database: database).execute(*ARGV).tap do |out|
9
- puts JSON.dump(out.respond_to?(:to_i) ? out.to_i : out.to_a) if out
10
- end
8
+ commands = {
9
+ database: ConcourseTechnician::Database.new,
10
+ volume_reaper: ConcourseTechnician::VolumeReaper.new
11
+ }
12
+
13
+ ConcourseTechnician::CLI.new(commands).execute(*ARGV).tap do |out|
14
+ puts JSON.dump(out.respond_to?(:to_i) ? out.to_i : out.to_a) if out
11
15
  end
@@ -12,7 +12,9 @@ Gem::Specification.new do |gem|
12
12
  gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
13
13
  gem.require_paths = ['lib']
14
14
 
15
+ gem.add_runtime_dependency 'btrfs', '~> 0.1', '>= 0.1.5'
15
16
  gem.add_runtime_dependency 'contracts', '~> 0.14', '>= 0.14.0'
16
17
  gem.add_runtime_dependency 'instacli', '~> 1.1', '>= 1.1.2'
17
18
  gem.add_runtime_dependency 'sequel', '~> 4.36', '>= 4.36.0'
19
+ gem.add_runtime_dependency 'systemized', '~> 0.2', '>= 0.2.4'
18
20
  end
@@ -2,3 +2,4 @@
2
2
  require_relative 'concourse-technician/cli'
3
3
  require_relative 'concourse-technician/database'
4
4
  require_relative 'concourse-technician/settings'
5
+ require_relative 'concourse-technician/volume_reaper'
@@ -0,0 +1,133 @@
1
+ require 'btrfs'
2
+ require 'contracts'
3
+ require 'fileutils'
4
+ require 'systemized'
5
+ require 'time'
6
+ require_relative 'settings'
7
+
8
+ module ConcourseTechnician
9
+ class VolumeReaper
10
+ include ::Contracts::Core
11
+ include ::Contracts::Builtin
12
+ include Settings
13
+
14
+ Contract None => ArrayOf[Time]
15
+ def timestamps
16
+ @timestamps ||= worker.journal.read(1000).map do |entry|
17
+ Time.parse entry.split.first
18
+ end.sort
19
+ end
20
+
21
+ Contract None => ArrayOf[Hash]
22
+ def recent_events
23
+ @recent_events ||= logs.read(100).map do |event|
24
+ begin
25
+ JSON.load event
26
+ rescue JSON::ParserError
27
+ nil
28
+ end
29
+ end.compact
30
+ end
31
+
32
+ Contract None => Any
33
+ def damaged
34
+ detected? ? exit : abort
35
+ end
36
+
37
+ Contract None => Any
38
+ def repair
39
+ detected ? repair! : abort
40
+ end
41
+
42
+ private
43
+
44
+ Contract RespondTo[:to_s] => Bool
45
+ def env?(key)
46
+ if ![nil, 'nil', 'false'].include? ENV[key.to_s.upcase]
47
+ true
48
+ else
49
+ block_given? ? yield : false
50
+ end
51
+ end
52
+
53
+ Contract None => Bool
54
+ def stagnant_logs?
55
+ env?(:stagnant_logs) do
56
+ (Time.now - timestamps.last) > (timestamps.last - timestamps.first)
57
+ end
58
+ end
59
+
60
+ Contract None => Bool
61
+ def reaping_failure?
62
+ env?(:reaping_failure) do
63
+ recent_events.any? do |event|
64
+ event['message'] == 'baggageclaim.tick.failed-to-reap'
65
+ end
66
+ end
67
+ end
68
+
69
+ Contract RespondTo[:to_s] => nil
70
+ def report(message)
71
+ STDERR.puts message.to_s unless env?(:QUIET)
72
+ end
73
+
74
+ Contract None => Bool
75
+ def detected?
76
+ stagnant_logs?.tap do |status|
77
+ report "Most recent log entry @ #{timestamps.last}"
78
+ report "Logs seem stagnant? #{status}"
79
+ end && reaping_failure?.tap do |status|
80
+ report "Recently volume reaping failure? #{status}"
81
+ end
82
+ end
83
+
84
+ Contract None => ::Systemized::Service
85
+ def worker
86
+ @worker = ::Systemized::Service.new('concourse-worker')
87
+ end
88
+
89
+ Contract None => ::Systemized::Journal
90
+ def logs
91
+ @logs ||= ::Systemized::Journal.new('concourse-worker', output: 'cat')
92
+ end
93
+
94
+ Contract None => String
95
+ def volumes_root
96
+ @volumes_root ||= ENV.fetch('VOLUMES_ROOT') do
97
+ settings.fetch('volumes_root') { '/concourse/volumes' }
98
+ end
99
+ end
100
+
101
+ Contract None => ArrayOf[::Btrfs::Subvolume]
102
+ def subvolumes
103
+ @subvolumes ||= ::Btrfs::Volume.new(volumes_root).subvolumes
104
+ end
105
+
106
+ Contract None => Maybe[Bool]
107
+ def reap_subvolumes
108
+ report "Reaping #{subvolumes.size} subvolumes..."
109
+ subvolumes.each(&:delete).all?(&:deleted?) unless env?(:NOOP)
110
+ end
111
+
112
+ Contract None => ArrayOf[String]
113
+ def dead_volumes
114
+ Dir.glob("#{volumes_root}/dead/*")
115
+ end
116
+
117
+ Contract None => Any
118
+ def reap_dead_volumes
119
+ report "Reaping #{dead_volumes.size} dead volumes..."
120
+ dead_volumes.each do |volume|
121
+ FileUtils.rmtree volume, verbose: env?(:QUIET), noop: env?(:NOOP)
122
+ end
123
+ end
124
+
125
+ Contract None => Any
126
+ def repair!
127
+ worker.stop if worker.active?
128
+ reap_subvolumes
129
+ reap_dead_volumes
130
+ worker.start
131
+ end
132
+ end
133
+ end
metadata CHANGED
@@ -1,15 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concourse-technician
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Olstrom
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-18 00:00:00.000000000 Z
11
+ date: 2016-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: btrfs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.1.5
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.5
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: contracts
15
35
  requirement: !ruby/object:Gem::Requirement
@@ -70,6 +90,26 @@ dependencies:
70
90
  - - ">="
71
91
  - !ruby/object:Gem::Version
72
92
  version: 4.36.0
93
+ - !ruby/object:Gem::Dependency
94
+ name: systemized
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '0.2'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 0.2.4
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.2'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 0.2.4
73
113
  description:
74
114
  email: chris@olstrom.com
75
115
  executables:
@@ -86,6 +126,7 @@ files:
86
126
  - lib/concourse-technician/cli.rb
87
127
  - lib/concourse-technician/database.rb
88
128
  - lib/concourse-technician/settings.rb
129
+ - lib/concourse-technician/volume_reaper.rb
89
130
  homepage: https://github.com/colstrom/concourse-technician
90
131
  licenses:
91
132
  - MIT
@@ -111,4 +152,3 @@ signing_key:
111
152
  specification_version: 4
112
153
  summary: Troubleshoot Concourse without fly
113
154
  test_files: []
114
- has_rdoc: