concourse-technician 0.3.4 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
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: