config_o_mat 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +26 -0
- data/Gemfile.lock +56 -0
- data/LICENSE +202 -0
- data/NOTICE +2 -0
- data/README.md +15 -0
- data/Rakefile +35 -0
- data/bin/config_o_mat-configurator +49 -0
- data/bin/config_o_mat-meta_configurator +49 -0
- data/config_o_mat.gemspec +49 -0
- data/design/configurator_lifecycle_test.dot +91 -0
- data/design/original_design.md +45 -0
- data/lib/config_o_mat/configurator/cond/first_run.rb +29 -0
- data/lib/config_o_mat/configurator/cond/next_state.rb +29 -0
- data/lib/config_o_mat/configurator/cond/profiles_to_apply.rb +29 -0
- data/lib/config_o_mat/configurator/cond/retries_left.rb +37 -0
- data/lib/config_o_mat/configurator/cond/services_to_reload.rb +29 -0
- data/lib/config_o_mat/configurator/cond.rb +17 -0
- data/lib/config_o_mat/configurator/memory.rb +93 -0
- data/lib/config_o_mat/configurator/op/apply_all_profiles.rb +35 -0
- data/lib/config_o_mat/configurator/op/commit_staged_profile.rb +35 -0
- data/lib/config_o_mat/configurator/op/compile_templates.rb +41 -0
- data/lib/config_o_mat/configurator/op/connect_to_appconfig.rb +35 -0
- data/lib/config_o_mat/configurator/op/generate_all_templates.rb +66 -0
- data/lib/config_o_mat/configurator/op/next_tick.rb +48 -0
- data/lib/config_o_mat/configurator/op/notify_systemd_start.rb +29 -0
- data/lib/config_o_mat/configurator/op/parse_cli.rb +93 -0
- data/lib/config_o_mat/configurator/op/refresh_all_profiles.rb +63 -0
- data/lib/config_o_mat/configurator/op/refresh_profile.rb +65 -0
- data/lib/config_o_mat/configurator/op/reload_one_service.rb +73 -0
- data/lib/config_o_mat/configurator/op/stage_one_profile.rb +33 -0
- data/lib/config_o_mat/configurator/op/wait_retry.rb +41 -0
- data/lib/config_o_mat/configurator/op.rb +17 -0
- data/lib/config_o_mat/configurator.rb +122 -0
- data/lib/config_o_mat/flip_flopper/cond/service_status.rb +29 -0
- data/lib/config_o_mat/flip_flopper/cond.rb +17 -0
- data/lib/config_o_mat/flip_flopper/memory.rb +51 -0
- data/lib/config_o_mat/flip_flopper/op/check_service_status.rb +72 -0
- data/lib/config_o_mat/flip_flopper/op/determine_running_instance.rb +56 -0
- data/lib/config_o_mat/flip_flopper/op/report_failure.rb +36 -0
- data/lib/config_o_mat/flip_flopper/op/start_activating_instance.rb +34 -0
- data/lib/config_o_mat/flip_flopper/op/stop_activating_instance.rb +34 -0
- data/lib/config_o_mat/flip_flopper/op/stop_initial_instance.rb +34 -0
- data/lib/config_o_mat/flip_flopper/op.rb +17 -0
- data/lib/config_o_mat/flip_flopper.rb +46 -0
- data/lib/config_o_mat/meta_configurator/memory.rb +73 -0
- data/lib/config_o_mat/meta_configurator/op/generate_systemd_config.rb +80 -0
- data/lib/config_o_mat/meta_configurator/op/parse_meta_cli.rb +103 -0
- data/lib/config_o_mat/meta_configurator/op.rb +17 -0
- data/lib/config_o_mat/meta_configurator.rb +44 -0
- data/lib/config_o_mat/shared/cond/early_exit.rb +29 -0
- data/lib/config_o_mat/shared/cond.rb +17 -0
- data/lib/config_o_mat/shared/op/load_meta_config.rb +188 -0
- data/lib/config_o_mat/shared/op.rb +17 -0
- data/lib/config_o_mat/shared/systemd_interface.rb +93 -0
- data/lib/config_o_mat/shared/types.rb +248 -0
- data/lib/config_o_mat/version.rb +19 -0
- data/lib/version.rb +19 -0
- data/systemd/teak-configurator-restart-service@.path +27 -0
- data/systemd/teak-configurator-restart-service@.service +21 -0
- data/systemd/teak-configurator-start-service@.path +27 -0
- data/systemd/teak-configurator-start-service@.service +21 -0
- data/systemd/teak-configurator-stop-service@.path +27 -0
- data/systemd/teak-configurator-stop-service@.service +21 -0
- data/systemd/teak-configurator.service +68 -0
- data/systemd/teak-metaconfigurator.service +57 -0
- metadata +213 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm/op_base'
|
18
|
+
|
19
|
+
module ConfigOMat
|
20
|
+
module Op
|
21
|
+
class RefreshAllProfiles < LifecycleVM::OpBase
|
22
|
+
reads :profile_defs, :applied_profiles, :client_id, :appconfig_client
|
23
|
+
writes :profiles_to_apply, :last_refresh_time
|
24
|
+
|
25
|
+
def call
|
26
|
+
self.profiles_to_apply = []
|
27
|
+
self.last_refresh_time = Time.now.to_i
|
28
|
+
|
29
|
+
profile_defs.each do |(profile_name, definition)|
|
30
|
+
request = {
|
31
|
+
application: definition.application, environment: definition.environment,
|
32
|
+
configuration: definition.profile, client_id: client_id
|
33
|
+
}
|
34
|
+
|
35
|
+
current_version = applied_profiles&.fetch(profile_name, nil)&.version
|
36
|
+
request[:client_configuration_version] = current_version if current_version
|
37
|
+
|
38
|
+
response =
|
39
|
+
begin
|
40
|
+
appconfig_client.get_configuration(request)
|
41
|
+
rescue StandardError => e
|
42
|
+
error profile_name, e
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
next if response.nil?
|
47
|
+
|
48
|
+
loaded_version = response.configuration_version
|
49
|
+
next if current_version && loaded_version == current_version
|
50
|
+
|
51
|
+
logger&.notice(
|
52
|
+
:updated_profile,
|
53
|
+
name: profile_name, previous_version: current_version, new_version: loaded_version
|
54
|
+
)
|
55
|
+
|
56
|
+
profiles_to_apply << LoadedProfile.new(
|
57
|
+
profile_name, loaded_version, response.content.read, response.content_type
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm/op_base'
|
18
|
+
|
19
|
+
module ConfigOMat
|
20
|
+
module Op
|
21
|
+
class RefreshProfile < LifecycleVM::OpBase
|
22
|
+
reads :profile_defs, :client_id, :applying_profile, :appconfig_client
|
23
|
+
writes :applying_profile
|
24
|
+
|
25
|
+
def call
|
26
|
+
profile_name = applying_profile.name
|
27
|
+
profile_version = applying_profile.version
|
28
|
+
definition = profile_defs[profile_name]
|
29
|
+
request = {
|
30
|
+
application: definition.application, environment: definition.environment,
|
31
|
+
configuration: definition.profile, client_id: client_id,
|
32
|
+
client_configuration_version: profile_version
|
33
|
+
}
|
34
|
+
|
35
|
+
response =
|
36
|
+
begin
|
37
|
+
appconfig_client.get_configuration(request)
|
38
|
+
rescue StandardError => e
|
39
|
+
error profile_name, e
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
return if response.nil? || errors?
|
44
|
+
loaded_version = response.configuration_version
|
45
|
+
|
46
|
+
if loaded_version == profile_version
|
47
|
+
logger&.warning(
|
48
|
+
:no_update,
|
49
|
+
name: profile_name, version: profile_version
|
50
|
+
)
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
logger&.notice(
|
55
|
+
:updated_profile,
|
56
|
+
name: profile_name, previous_version: profile_version, new_version: loaded_version
|
57
|
+
)
|
58
|
+
|
59
|
+
self.applying_profile = LoadedProfile.new(
|
60
|
+
profile_name, loaded_version, response.content.read, response.content_type
|
61
|
+
)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm/op_base'
|
18
|
+
|
19
|
+
require 'config_o_mat/flip_flopper'
|
20
|
+
|
21
|
+
require 'dbus'
|
22
|
+
|
23
|
+
module ConfigOMat
|
24
|
+
module Op
|
25
|
+
class ReloadOneService < LifecycleVM::OpBase
|
26
|
+
reads :services_to_reload, :runtime_directory, :service_defs, :systemd_interface
|
27
|
+
writes :services_to_reload
|
28
|
+
|
29
|
+
def call
|
30
|
+
service = services_to_reload.pop
|
31
|
+
service_def = service_defs[service]
|
32
|
+
|
33
|
+
if service_def.restart_mode == :restart
|
34
|
+
do_restart(service, service_def)
|
35
|
+
else
|
36
|
+
do_flip_flop(service, service_def)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def do_restart(service, service_def)
|
43
|
+
unit = service_def.systemd_unit
|
44
|
+
|
45
|
+
file_path = File.join(runtime_directory, unit + '.restart')
|
46
|
+
|
47
|
+
logger&.notice(
|
48
|
+
:service_restart,
|
49
|
+
name: service, systemd_unit: unit, touched_path: file_path
|
50
|
+
)
|
51
|
+
|
52
|
+
FileUtils.touch(file_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
def do_flip_flop(service, service_def)
|
56
|
+
mem = ConfigOMat::FlipFlopper::Memory.new(
|
57
|
+
runtime_directory: runtime_directory,
|
58
|
+
service: service_def.systemd_unit,
|
59
|
+
systemd_interface: systemd_interface,
|
60
|
+
logger: logger
|
61
|
+
)
|
62
|
+
vm = ConfigOMat::FlipFlopper::VM.new(mem)
|
63
|
+
vm.call
|
64
|
+
|
65
|
+
if vm.errors?
|
66
|
+
vm.errors.each do |(key, value)|
|
67
|
+
value.each { |v| error key, v }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm/op_base'
|
18
|
+
|
19
|
+
module ConfigOMat
|
20
|
+
module Op
|
21
|
+
class StageOneProfile < LifecycleVM::OpBase
|
22
|
+
reads :profiles_to_apply
|
23
|
+
writes :applying_profile, :profiles_to_apply
|
24
|
+
|
25
|
+
def call
|
26
|
+
self.applying_profile = profiles_to_apply.pop
|
27
|
+
|
28
|
+
# We defer error checking to GenerateAllTemplates so that even if errored the profile gets set as
|
29
|
+
# the applying_profile, which simplifies retry logic.
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm/op_base'
|
18
|
+
|
19
|
+
module ConfigOMat
|
20
|
+
module Op
|
21
|
+
class WaitRetry < LifecycleVM::OpBase
|
22
|
+
reads :retry_wait, :retry_count, :retries_left
|
23
|
+
writes :retries_left
|
24
|
+
|
25
|
+
def call
|
26
|
+
# Exponential backoff
|
27
|
+
wait = retry_wait * (2**(retry_count - retries_left))
|
28
|
+
|
29
|
+
# With jitter
|
30
|
+
wait += rand(retry_wait + 1) - (retry_wait / 2.0)
|
31
|
+
|
32
|
+
logger&.notice(:retry_wait, wait: wait)
|
33
|
+
|
34
|
+
# Calling Kernel.sleep directly for easy test stubbing
|
35
|
+
Kernel.sleep wait
|
36
|
+
|
37
|
+
self.retries_left -= 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
Dir[File.join(__dir__, 'op', '*')].sort.each { |file| require file }
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm'
|
18
|
+
|
19
|
+
require 'config_o_mat/shared/cond'
|
20
|
+
require 'config_o_mat/shared/op'
|
21
|
+
require 'config_o_mat/configurator/op'
|
22
|
+
require 'config_o_mat/configurator/cond'
|
23
|
+
require 'config_o_mat/configurator/memory'
|
24
|
+
|
25
|
+
module ConfigOMat
|
26
|
+
module Configurator
|
27
|
+
class VM < LifecycleVM::VM
|
28
|
+
VERSION = "0.0.1"
|
29
|
+
|
30
|
+
memory_class ConfigOMat::Configurator::Memory
|
31
|
+
on_op_failure :op_failure
|
32
|
+
terminal :fail
|
33
|
+
|
34
|
+
on :start, do: Op::ParseCli, then: {
|
35
|
+
case: Cond::EarlyExit,
|
36
|
+
when: {
|
37
|
+
true => :exit,
|
38
|
+
false => :reading_meta_config
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
on :reading_meta_config, do: Op::LoadMetaConfig, then: :compiling_templates
|
43
|
+
|
44
|
+
on :compiling_templates, do: Op::CompileTemplates, then: :connecting_to_appconfig
|
45
|
+
|
46
|
+
on :connecting_to_appconfig, do: Op::ConnectToAppconfig, then: :refreshing_profiles
|
47
|
+
|
48
|
+
on :refreshing_profiles,
|
49
|
+
do: Op::RefreshAllProfiles,
|
50
|
+
then: {
|
51
|
+
case: Cond::FirstRun,
|
52
|
+
when: {
|
53
|
+
true => :initial_applying_profiles,
|
54
|
+
false => :applying_profiles
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
on :initial_applying_profiles, do: Op::ApplyAllProfiles, then: :generating_templates
|
59
|
+
|
60
|
+
on :applying_profiles,
|
61
|
+
then: {
|
62
|
+
case: Cond::ProfilesToApply,
|
63
|
+
when: {
|
64
|
+
true => :applying_profile,
|
65
|
+
false => :running
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
on :applying_profile, do: Op::StageOneProfile, then: :generating_templates
|
70
|
+
|
71
|
+
on :generating_templates, do: Op::GenerateAllTemplates, then: {
|
72
|
+
case: Cond::FirstRun,
|
73
|
+
when: {
|
74
|
+
true => :notifying_systemd,
|
75
|
+
false => :reloading_services
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
on :notifying_systemd, do: Op::NotifySystemdStart, then: :running
|
80
|
+
|
81
|
+
on :reloading_services,
|
82
|
+
then: {
|
83
|
+
case: Cond::ServicesToReload,
|
84
|
+
when: {
|
85
|
+
true => :reloading_service,
|
86
|
+
false => { do: Op::CommitStagedProfile, then: :applying_profiles }
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
on :reloading_service, do: Op::ReloadOneService, then: :reloading_services
|
91
|
+
|
92
|
+
on :running,
|
93
|
+
do: Op::NextTick,
|
94
|
+
then: {
|
95
|
+
case: Cond::NextState,
|
96
|
+
when: {
|
97
|
+
refreshing_profiles: :refreshing_profiles,
|
98
|
+
graceful_shutdown: :exit,
|
99
|
+
fail: :fail,
|
100
|
+
running: :running
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
on :op_failure,
|
105
|
+
then: {
|
106
|
+
case: Cond::FirstRun,
|
107
|
+
when: {
|
108
|
+
true => :fail,
|
109
|
+
false => {
|
110
|
+
case: Cond::RetriesLeft,
|
111
|
+
when: {
|
112
|
+
true => { do: Op::WaitRetry, then: :refreshing_profile },
|
113
|
+
false => :fail
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
on :refreshing_profile, do: Op::RefreshProfile, then: :applying_profile
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm/cond_base'
|
18
|
+
|
19
|
+
module ConfigOMat
|
20
|
+
module Cond
|
21
|
+
class ServiceStatus < LifecycleVM::CondBase
|
22
|
+
reads :activation_status
|
23
|
+
|
24
|
+
def call
|
25
|
+
activation_status
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
Dir[File.join(__dir__, 'cond', '*')].sort.each { |file| require file }
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm'
|
18
|
+
|
19
|
+
module ConfigOMat
|
20
|
+
module FlipFlopper
|
21
|
+
class Memory < LifecycleVM::Memory
|
22
|
+
attr_reader :systemd_interface, :service, :runtime_directory
|
23
|
+
attr_accessor :running_instance, :activating_instance, :activation_status, :activating_interface,
|
24
|
+
:min_wait, :max_wait
|
25
|
+
|
26
|
+
def initialize(
|
27
|
+
systemd_interface: nil,
|
28
|
+
service: nil,
|
29
|
+
min_wait: 5,
|
30
|
+
max_wait: 30,
|
31
|
+
runtime_directory: nil,
|
32
|
+
running_instance: nil,
|
33
|
+
activating_instance: nil,
|
34
|
+
activation_status: nil,
|
35
|
+
activating_interface: nil,
|
36
|
+
logger: nil
|
37
|
+
)
|
38
|
+
@systemd_interface = systemd_interface
|
39
|
+
@service = service
|
40
|
+
@min_wait = min_wait
|
41
|
+
@max_wait = max_wait
|
42
|
+
@runtime_directory = runtime_directory
|
43
|
+
@running_instance = running_instance
|
44
|
+
@activating_instance = activating_instance
|
45
|
+
@activation_status = activation_status
|
46
|
+
@activating_interface = activating_interface
|
47
|
+
@logger = logger
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm/op_base'
|
18
|
+
|
19
|
+
module ConfigOMat
|
20
|
+
module Op
|
21
|
+
class CheckServiceStatus < LifecycleVM::OpBase
|
22
|
+
reads :service, :activating_instance, :activating_interface, :systemd_interface,
|
23
|
+
:min_wait, :max_wait
|
24
|
+
writes :activating_interface, :activation_status, :min_wait, :max_wait
|
25
|
+
|
26
|
+
def call
|
27
|
+
if min_wait > 0
|
28
|
+
do_sleep(min_wait)
|
29
|
+
else
|
30
|
+
do_sleep(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
instance_name = "#{service}#{activating_instance}"
|
34
|
+
|
35
|
+
if !activating_interface
|
36
|
+
self.activating_interface = systemd_interface.service_interface(instance_name)
|
37
|
+
end
|
38
|
+
|
39
|
+
if !activating_interface
|
40
|
+
logger&.error(:ipc_failure, name: instance_name)
|
41
|
+
self.activation_status = :failed
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
reported_status = activating_interface['ActiveState']
|
46
|
+
|
47
|
+
logger&.info(:service_status, name: instance_name, status: reported_status)
|
48
|
+
|
49
|
+
if reported_status == 'active'
|
50
|
+
self.activation_status = :started
|
51
|
+
elsif reported_status == 'activating'
|
52
|
+
if max_wait > 0
|
53
|
+
self.activation_status = :starting
|
54
|
+
else
|
55
|
+
self.activation_status = :timed_out
|
56
|
+
end
|
57
|
+
else
|
58
|
+
self.activation_status = :failed
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def do_sleep(secs)
|
65
|
+
# I'm calling Kernel.sleep directly so we can easily stub it out.
|
66
|
+
::Kernel.sleep secs
|
67
|
+
self.min_wait -= secs
|
68
|
+
self.max_wait -= secs
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm/op_base'
|
18
|
+
|
19
|
+
module ConfigOMat
|
20
|
+
module Op
|
21
|
+
class DetermineRunningInstance < LifecycleVM::OpBase
|
22
|
+
reads :systemd_interface, :service
|
23
|
+
writes :running_instance, :activating_instance
|
24
|
+
|
25
|
+
RUNNING_STATES = %w[active activating reloading].freeze
|
26
|
+
|
27
|
+
def call
|
28
|
+
i1_name = "#{service}1"
|
29
|
+
i1_status = systemd_interface.service_status(i1_name)
|
30
|
+
logger&.info(:service_status, name: i1_name, status: i1_status)
|
31
|
+
|
32
|
+
i2_name = "#{service}2"
|
33
|
+
i2_status = systemd_interface.service_status(i2_name)
|
34
|
+
logger&.info(:service_status, name: i2_name, status: i2_status)
|
35
|
+
|
36
|
+
i1_running = RUNNING_STATES.include?(i1_status)
|
37
|
+
i2_running = RUNNING_STATES.include?(i2_status)
|
38
|
+
|
39
|
+
if i1_running && i2_running
|
40
|
+
error :service, 'both instances are currently running!'
|
41
|
+
elsif i1_running
|
42
|
+
self.activating_instance = 2
|
43
|
+
self.running_instance = 1
|
44
|
+
elsif i2_running
|
45
|
+
self.activating_instance = 1
|
46
|
+
self.running_instance = 2
|
47
|
+
else
|
48
|
+
# If neither version is up, attempt to bring up instance 1. Our attempt to stop
|
49
|
+
# instance 2 will be a noop.
|
50
|
+
self.activating_instance = 1
|
51
|
+
self.running_instance = 2
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2021 Teak.io, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'lifecycle_vm/op_base'
|
18
|
+
|
19
|
+
module ConfigOMat
|
20
|
+
module Op
|
21
|
+
class ReportFailure < LifecycleVM::OpBase
|
22
|
+
reads :activation_status
|
23
|
+
|
24
|
+
def call
|
25
|
+
case activation_status
|
26
|
+
when :failed
|
27
|
+
error :service, 'failed to start service instance'
|
28
|
+
when :timed_out
|
29
|
+
error :service, 'service instance did not start within timeout'
|
30
|
+
else
|
31
|
+
error :service, "service instance failed due to an unknown error (#{activation_status})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|