foreman_maintain 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +193 -0
- data/bin/foreman-maintain +9 -0
- data/definitions/checks/foreman_tasks_not_paused.rb +14 -0
- data/definitions/checks/foreman_tasks_not_running.rb +10 -0
- data/definitions/features/downstream.rb +17 -0
- data/definitions/features/foreman_1_11_x.rb +7 -0
- data/definitions/features/foreman_1_7_x.rb +7 -0
- data/definitions/features/foreman_database.rb +15 -0
- data/definitions/features/foreman_tasks.rb +22 -0
- data/definitions/features/upstream.rb +7 -0
- data/definitions/procedures/foreman_tasks_resume.rb +13 -0
- data/definitions/scenarios/pre_upgrade_check_foreman_1_14.rb +12 -0
- data/definitions/scenarios/pre_upgrade_check_satellite_6_0_z.rb +12 -0
- data/definitions/scenarios/pre_upgrade_check_satellite_6_1.rb +12 -0
- data/definitions/scenarios/pre_upgrade_check_satellite_6_1_z.rb +12 -0
- data/definitions/scenarios/pre_upgrade_check_satellite_6_2.rb +12 -0
- data/definitions/scenarios/pre_upgrade_check_satellite_6_2_z.rb +12 -0
- data/definitions/scenarios/pre_upgrade_check_satellite_6_3.rb +12 -0
- data/lib/foreman_maintain.rb +54 -0
- data/lib/foreman_maintain/check.rb +34 -0
- data/lib/foreman_maintain/cli.rb +14 -0
- data/lib/foreman_maintain/cli/base.rb +47 -0
- data/lib/foreman_maintain/cli/health_command.rb +39 -0
- data/lib/foreman_maintain/cli/upgrade_command.rb +57 -0
- data/lib/foreman_maintain/concerns/finders.rb +69 -0
- data/lib/foreman_maintain/concerns/logger.rb +13 -0
- data/lib/foreman_maintain/concerns/metadata.rb +124 -0
- data/lib/foreman_maintain/concerns/system_helpers.rb +93 -0
- data/lib/foreman_maintain/config.rb +17 -0
- data/lib/foreman_maintain/detector.rb +146 -0
- data/lib/foreman_maintain/executable.rb +44 -0
- data/lib/foreman_maintain/feature.rb +22 -0
- data/lib/foreman_maintain/logger.rb +11 -0
- data/lib/foreman_maintain/procedure.rb +8 -0
- data/lib/foreman_maintain/reporter.rb +18 -0
- data/lib/foreman_maintain/reporter/cli_reporter.rb +177 -0
- data/lib/foreman_maintain/runner.rb +39 -0
- data/lib/foreman_maintain/runner/execution.rb +74 -0
- data/lib/foreman_maintain/scenario.rb +46 -0
- data/lib/foreman_maintain/top_level_modules.rb +13 -0
- data/lib/foreman_maintain/version.rb +3 -0
- metadata +173 -0
data/README.md
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
# Foreman Maintenance
|
2
|
+
|
3
|
+
`foreman_maintain` aims to provide various features that helps keeping the
|
4
|
+
Foreman/Satellite up and running. It supports multiple versions and subparts
|
5
|
+
of the Foreman infrastructure, including server or smart proxy and is smart
|
6
|
+
enough to provide the right tools for the specific version.
|
7
|
+
|
8
|
+
## Usage
|
9
|
+
|
10
|
+
```
|
11
|
+
Subcommands:
|
12
|
+
health Health related commands
|
13
|
+
list-checks List the checks based on criteria
|
14
|
+
list-tags List the tags to use for filtering checks
|
15
|
+
check Run the health checks against the system
|
16
|
+
--tags tags Limit only for specific set of tags
|
17
|
+
|
18
|
+
upgrade Upgrade related commands
|
19
|
+
list-versions List versions this system is upgradable to
|
20
|
+
check TARGET_VERSION Run pre-upgrade checks for upgradeing to specified version
|
21
|
+
```
|
22
|
+
|
23
|
+
## Implementation
|
24
|
+
|
25
|
+
`foreman_maintain` maps the CLI commands into definitions. This allows to keep the set
|
26
|
+
of the commands the user needs to know immutable from version-specific changes. The mapping
|
27
|
+
between the CLI commands and definitions is made by defining various metadata.
|
28
|
+
|
29
|
+
## Definitions
|
30
|
+
|
31
|
+
There are various kinds of definitions possible:
|
32
|
+
|
33
|
+
* **Features** - aspects that can be present on the system. It can be
|
34
|
+
service (foreman, foreman-proxy), a feature (some Foreman plugin),
|
35
|
+
a link to external systems (e.g. registered foreman proxy, compute resource)
|
36
|
+
or another aspect that can be subject of health checks and maintenance procedures.
|
37
|
+
* **Checks** - definitions of health checks to indicate health of the system against the present features
|
38
|
+
* **Procedures** - steps for performing specific operations on the system
|
39
|
+
* **Scenarios** - combinations of checks and procedures to achieve some goal
|
40
|
+
|
41
|
+
The definitions for this components are present in `definitions` folder.
|
42
|
+
|
43
|
+
### Features
|
44
|
+
|
45
|
+
Before `foreman_maintain` starts, it takes the set of `features` definition
|
46
|
+
and determines their pesence by running their `confine` blocks against
|
47
|
+
the system.
|
48
|
+
|
49
|
+
The `confine` block can run an external command to check if the feature
|
50
|
+
is there, or it can check present of other features.
|
51
|
+
|
52
|
+
A feature can define additional methods that can be used across other
|
53
|
+
definitions.
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
class Features::Foreman < ForemanMaintain::Feature
|
57
|
+
label :foreman
|
58
|
+
|
59
|
+
confine do
|
60
|
+
check_min_version('foreman', '1.7')
|
61
|
+
end
|
62
|
+
|
63
|
+
# helper method that can be used in other definitions like this:
|
64
|
+
#
|
65
|
+
# feature(:foreman).running?
|
66
|
+
def running?
|
67
|
+
execute?('systemctl foreman status')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
The features can inherit from each other, which allows overriding
|
73
|
+
methods for older versions, when newer version of the feature is present
|
74
|
+
in the system. This way, we shield the other definitions (checks, procedures,
|
75
|
+
scenarios) from version-specific nuances.
|
76
|
+
|
77
|
+
### Checks
|
78
|
+
|
79
|
+
Checks define assertions to determine status of the system.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class Checks::ForemanIsRuning < ForemanMaintain::Check
|
83
|
+
for_feature :foreman
|
84
|
+
|
85
|
+
description 'check foreman service is running'
|
86
|
+
|
87
|
+
tags :basic
|
88
|
+
|
89
|
+
def run
|
90
|
+
# we are using methods of a feature.
|
91
|
+
assert(feature(:foreman).running?
|
92
|
+
'There are currently paused tasks in the system')
|
93
|
+
end
|
94
|
+
|
95
|
+
# we can define additional steps to be executed after this check is finished
|
96
|
+
# based on the result
|
97
|
+
def next_steps
|
98
|
+
[procedure(Procedures::ForemanStart)] if fail?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
Similarly as features, also checks (and in fact all definitions) can used
|
104
|
+
`label`, `description` `confine` and `tags` keyword to describe themselves.
|
105
|
+
|
106
|
+
Every definition has a `label` (if not stated explicitly, it's
|
107
|
+
determined from the class name).
|
108
|
+
|
109
|
+
### Procedures
|
110
|
+
|
111
|
+
Procedure defines some operation that can be performed against the system.
|
112
|
+
It can be part of a scenario or be linked from a check as a remediation step.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
class Procedures::ForemanStart < ForemanMaintain::Procedure
|
116
|
+
for_feature :foreman
|
117
|
+
|
118
|
+
description 'start foreman service'
|
119
|
+
|
120
|
+
def run
|
121
|
+
feature(:foreman).start
|
122
|
+
end
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
### Scenarios
|
127
|
+
|
128
|
+
Scenarios represent a composition of various steps (checks and procedures) to
|
129
|
+
achieve some complex maintenance operation in the system (such as upgrade).
|
130
|
+
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
class Scenarios::PreUpgradeCheckForeman_1_14 < ForemanMaintain::Scenario
|
134
|
+
description 'checks before upgrading to Foreman 1.14'
|
135
|
+
|
136
|
+
confine do
|
137
|
+
feature(:upstream)
|
138
|
+
end
|
139
|
+
|
140
|
+
tags :pre_upgrade_check
|
141
|
+
|
142
|
+
# Method to be called when composing the steps of the scenario
|
143
|
+
def compose
|
144
|
+
# we can search for the checks by metadata
|
145
|
+
steps.concat(find_checks(:basic))
|
146
|
+
end
|
147
|
+
end
|
148
|
+
```
|
149
|
+
|
150
|
+
## Implementation components
|
151
|
+
|
152
|
+
In order to process the definitions, there are other components present in the `lib` directory.
|
153
|
+
|
154
|
+
* **Detector** - searches the checks/procedures/scenarios based on metadata & available features
|
155
|
+
* **Runner** - executes the scenario
|
156
|
+
* **Reporter** - reports the results of the run. It's possible to define
|
157
|
+
multiple reporters, based on the current use case (CLI, reporting to monitoring tool)
|
158
|
+
* **Cli** - Clamp-based command line infrastructure, mapping the definitions
|
159
|
+
to user commands.
|
160
|
+
|
161
|
+
## Testing
|
162
|
+
|
163
|
+
Since a single version of `foreman_maintain` is meant to be used against multiple versions and
|
164
|
+
components combinations, the testing is a crucial part of the process.
|
165
|
+
|
166
|
+
There are multiple kind of tests `foreman_maintain`:
|
167
|
+
|
168
|
+
* unit tests for implementation components - can be found in `test/lib`
|
169
|
+
* this tests are independent of the real-world definitions and are focused
|
170
|
+
on the internal implementation (metadata definitions, features detection)
|
171
|
+
* unit tests for definitions - can be found in `test/definitions`
|
172
|
+
* this tests are focusing on testing of the code in definitions directory.
|
173
|
+
There is an infrastructure to simulate various combinations of features without
|
174
|
+
needing for actually having them present for development
|
175
|
+
* bats test - TBD
|
176
|
+
* to achieve stability, we also want to include bats tests as part of the infrastructure,
|
177
|
+
perhaps in combination with ansible playbooks to make the testing against real-world
|
178
|
+
instances as easy as possible.
|
179
|
+
|
180
|
+
Execute `rake` to run the tests.
|
181
|
+
|
182
|
+
## Planned commands:
|
183
|
+
|
184
|
+
```
|
185
|
+
foreman-maintain health [check|fix]
|
186
|
+
foreman-maintain upgrade [check|run|abort] [foreman_1_14, satellite_6_1, satellite_6_2]
|
187
|
+
foreman-maintain maintenance-mode [on|off]
|
188
|
+
foreman-maintain backup [save|restore]
|
189
|
+
foreman-maintain monitor [display|upload]
|
190
|
+
foreman-maintain debug [save|upload|tail]
|
191
|
+
foreman-maintain console
|
192
|
+
foreman-maintain config
|
193
|
+
```
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Checks::ForemanTasksNotPaused < ForemanMaintain::Check
|
2
|
+
for_feature :foreman_tasks
|
3
|
+
description 'check for paused tasks'
|
4
|
+
tags :basic
|
5
|
+
|
6
|
+
def run
|
7
|
+
assert(feature(:foreman_tasks).paused_tasks_count == 0,
|
8
|
+
'There are currently paused tasks in the system')
|
9
|
+
end
|
10
|
+
|
11
|
+
def next_steps
|
12
|
+
[procedure(Procedures::ForemanTasksResume)] if fail?
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class Checks::ForemanTasksNotRunning < ForemanMaintain::Check
|
2
|
+
for_feature :foreman_tasks
|
3
|
+
description 'check for running tasks'
|
4
|
+
tags :pre_upgrade
|
5
|
+
|
6
|
+
def run
|
7
|
+
assert(feature(:foreman_tasks).running_tasks_count == 0,
|
8
|
+
'There are actively running tasks in the system')
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Features::Downstream < ForemanMaintain::Feature
|
2
|
+
label :downstream
|
3
|
+
|
4
|
+
confine do
|
5
|
+
downstream_installation?
|
6
|
+
end
|
7
|
+
|
8
|
+
def current_version
|
9
|
+
@current_version ||= rpm_version('satellite') || version_from_source
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def version_from_source
|
15
|
+
version(File.read('/usr/share/foreman/lib/satellite/version.rb')[/6\.\d\.\d/])
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Features::ForemanDatabase < ForemanMaintain::Feature
|
2
|
+
label :foreman_database
|
3
|
+
|
4
|
+
confine do
|
5
|
+
File.exist?('/etc/foreman/database.yml')
|
6
|
+
end
|
7
|
+
|
8
|
+
def query(sql)
|
9
|
+
parse_csv(psql(%{COPY (#{sql}) TO STDOUT WITH CSV HEADER)}))
|
10
|
+
end
|
11
|
+
|
12
|
+
def psql(query)
|
13
|
+
execute("su - postgres -c 'psql -d foreman'", query)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Features::ForemanTasks < ForemanMaintain::Feature
|
2
|
+
label :foreman_tasks
|
3
|
+
|
4
|
+
confine do
|
5
|
+
check_min_version('ruby193-rubygem-foreman-tasks', '0.6') ||
|
6
|
+
check_min_version('tfm-rubygem-foreman-tasks', '0.7')
|
7
|
+
end
|
8
|
+
|
9
|
+
def running_tasks_count
|
10
|
+
# feature(:foreman_database).query(<<-SQL).first['count'].to_i
|
11
|
+
# SELECT count(*) AS count FROM foreman_tasks_tasks WHERE state in ('running', 'paused')
|
12
|
+
# SQL
|
13
|
+
0
|
14
|
+
end
|
15
|
+
|
16
|
+
def paused_tasks_count
|
17
|
+
# feature(:foreman_database).query(<<-SQL).first['count'].to_i
|
18
|
+
# SELECT count(*) AS count FROM foreman_tasks_tasks WHERE state in ('running', 'paused')
|
19
|
+
# SQL
|
20
|
+
5
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Procedures::ForemanTasksResume < ForemanMaintain::Procedure
|
2
|
+
for_feature :foreman_tasks
|
3
|
+
description 'resume paused tasks'
|
4
|
+
|
5
|
+
def run
|
6
|
+
say 'resuming paused tasks'
|
7
|
+
sleep 2
|
8
|
+
say 'hold on'
|
9
|
+
sleep 2
|
10
|
+
say 'almost there'
|
11
|
+
sleep 2
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Scenarios::PreUpgradeCheckForeman_1_14 < ForemanMaintain::Scenario
|
2
|
+
description 'checks before upgrading to Foreman 1.14'
|
3
|
+
confine do
|
4
|
+
feature(:upstream)
|
5
|
+
end
|
6
|
+
|
7
|
+
tags :pre_upgrade_check
|
8
|
+
|
9
|
+
def compose
|
10
|
+
steps.concat(find_checks(:basic))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Scenarios::PreUpgradeCheckSatellite_6_0_z < ForemanMaintain::Scenario
|
2
|
+
tags :pre_upgrade_check, :satellite_6_0_z
|
3
|
+
description 'checks before upgrading to Satellite 6.0'
|
4
|
+
confine do
|
5
|
+
feature(:downstream) && feature(:downstream).current_version.to_s.start_with?('6.0.')
|
6
|
+
end
|
7
|
+
|
8
|
+
def compose
|
9
|
+
steps.concat(find_checks(:basic))
|
10
|
+
steps.concat(find_checks(:pre_upgrade))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Scenarios::PreUpgradeCheckSatellite_6_1 < ForemanMaintain::Scenario
|
2
|
+
tags :pre_upgrade_check, :satellite_6_1
|
3
|
+
description 'checks before upgrading to Satellite 6.1'
|
4
|
+
confine do
|
5
|
+
feature(:downstream) && feature(:downstream).current_version.to_s.start_with?('6.0.')
|
6
|
+
end
|
7
|
+
|
8
|
+
def compose
|
9
|
+
steps.concat(find_checks(:basic))
|
10
|
+
steps.concat(find_checks(:pre_upgrade))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Scenarios::PreUpgradeCheckSatellite_6_1_z < ForemanMaintain::Scenario
|
2
|
+
tags :pre_upgrade_check, :satellite_6_1_z
|
3
|
+
description 'checks before upgrading to Satellite 6.1.z'
|
4
|
+
confine do
|
5
|
+
feature(:downstream) && feature(:downstream).current_version.to_s.start_with?('6.1.')
|
6
|
+
end
|
7
|
+
|
8
|
+
def compose
|
9
|
+
steps.concat(find_checks(:basic))
|
10
|
+
steps.concat(find_checks(:pre_upgrade))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Scenarios::PreUpgradeCheckSatellite_6_2 < ForemanMaintain::Scenario
|
2
|
+
tags :pre_upgrade_check, :satellite_6_2
|
3
|
+
description 'checks before upgrading to Satellite 6.2'
|
4
|
+
confine do
|
5
|
+
feature(:downstream) && feature(:downstream).current_version.to_s.start_with?('6.1.')
|
6
|
+
end
|
7
|
+
|
8
|
+
def compose
|
9
|
+
steps.concat(find_checks(:basic))
|
10
|
+
steps.concat(find_checks(:pre_upgrade))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Scenarios::PreUpgradeCheckSatellite_6_2_z < ForemanMaintain::Scenario
|
2
|
+
tags :pre_upgrade_check, :satellite_6_2_z
|
3
|
+
description 'checks before upgrading to Satellite 6.2.z'
|
4
|
+
confine do
|
5
|
+
feature(:downstream) && feature(:downstream).current_version.to_s.start_with?('6.2.')
|
6
|
+
end
|
7
|
+
|
8
|
+
def compose
|
9
|
+
steps.concat(find_checks(:basic))
|
10
|
+
steps.concat(find_checks(:pre_upgrade))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Scenarios::PreUpgradeCheckSatellite_6_3 < ForemanMaintain::Scenario
|
2
|
+
tags :pre_upgrade_check, :satellite_6_3
|
3
|
+
description 'checks before upgrading to Satellite 6.3'
|
4
|
+
confine do
|
5
|
+
feature(:downstream) && feature(:downstream).current_version.to_s.start_with?('6.2.')
|
6
|
+
end
|
7
|
+
|
8
|
+
def compose
|
9
|
+
steps.concat(find_checks(:basic))
|
10
|
+
steps.concat(find_checks(:pre_upgrade))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module ForemanMaintain
|
2
|
+
require 'foreman_maintain/concerns/logger'
|
3
|
+
require 'foreman_maintain/concerns/metadata'
|
4
|
+
require 'foreman_maintain/concerns/system_helpers'
|
5
|
+
require 'foreman_maintain/concerns/finders'
|
6
|
+
require 'foreman_maintain/top_level_modules'
|
7
|
+
require 'foreman_maintain/config'
|
8
|
+
require 'foreman_maintain/detector'
|
9
|
+
require 'foreman_maintain/feature'
|
10
|
+
require 'foreman_maintain/executable'
|
11
|
+
require 'foreman_maintain/check'
|
12
|
+
require 'foreman_maintain/procedure'
|
13
|
+
require 'foreman_maintain/scenario'
|
14
|
+
require 'foreman_maintain/runner'
|
15
|
+
require 'foreman_maintain/reporter'
|
16
|
+
|
17
|
+
class << self
|
18
|
+
attr_accessor :config
|
19
|
+
|
20
|
+
def setup(configuration = {})
|
21
|
+
self.config = Config.new(configuration)
|
22
|
+
load_definitions
|
23
|
+
end
|
24
|
+
|
25
|
+
def load_definitions
|
26
|
+
# we need to add the load paths first, in case there is crossreferencing
|
27
|
+
# between the definitions directories
|
28
|
+
$LOAD_PATH.concat(config.definitions_dirs)
|
29
|
+
config.definitions_dirs.each do |definitions_dir|
|
30
|
+
Dir.glob(File.join(definitions_dir, '**', '*.rb')).each { |f| require f }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def detector
|
35
|
+
@detector ||= Detector.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def available_features(*args)
|
39
|
+
detector.available_features(*args)
|
40
|
+
end
|
41
|
+
|
42
|
+
def available_scenarios(*args)
|
43
|
+
detector.available_scenarios(*args)
|
44
|
+
end
|
45
|
+
|
46
|
+
def available_checks(*args)
|
47
|
+
detector.available_checks(*args)
|
48
|
+
end
|
49
|
+
|
50
|
+
def available_procedures(*args)
|
51
|
+
detector.available_procedures(*args)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|