smart_proxy_acd 0.1.0 → 0.4.0
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 +4 -4
- data/README.md +0 -1
- data/lib/smart_proxy_acd/acd.rb +13 -2
- data/lib/smart_proxy_acd/acd_main.rb +11 -0
- data/lib/smart_proxy_acd/acd_runner.rb +164 -0
- data/lib/smart_proxy_acd/acd_task_launcher.rb +27 -0
- data/lib/smart_proxy_acd/version.rb +1 -1
- data/settings.d/acd.yml.example +2 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 183250a25f2479402b6eb73acd841ec985da00ebe17cb4b836df7b1e3d37ae48
|
4
|
+
data.tar.gz: d9b0c52df1fad8c9a998930252617eb971a8319a3f53fdd0e910b17bcef8b439
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88664606e79721dc883ee637bf749f54d6bfd3481ba42366abb4c0725a727fad4ec94d1029b25f0142b889b6bcdbde07f6e1142f419a939e8b3d4ae9ccddc5fa
|
7
|
+
data.tar.gz: 23cc133598f5d3888e0298bf5b2c3786d6a429ff6ba3625d673efdc0f61f338e64d749811c8dcbab8ff0cce544d7ec5672c813dbb38492cf2293f16d59c30f33
|
data/README.md
CHANGED
@@ -14,7 +14,6 @@ This plug-in adds support for [Application Centric Deployment](https://github.co
|
|
14
14
|
|
15
15
|
We expect your proxy to also have
|
16
16
|
[smart_proxy_dynflow](https://github.com/theforeman/smart_proxy_dynflow)
|
17
|
-
and [foreman-tasks-core](https://github.com/theforeman/foreman-tasks) as
|
18
17
|
a gem requirement.
|
19
18
|
|
20
19
|
### Get the code
|
data/lib/smart_proxy_acd/acd.rb
CHANGED
@@ -5,8 +5,19 @@ module Proxy
|
|
5
5
|
# Implement a SmartProxy Plugin
|
6
6
|
class Plugin < ::Proxy::Plugin
|
7
7
|
plugin 'acd', Proxy::Acd::VERSION
|
8
|
-
|
9
|
-
|
8
|
+
rackup_path File.expand_path('acd_http_config.ru', __dir__)
|
9
|
+
|
10
|
+
load_classes do
|
11
|
+
require 'smart_proxy_dynflow'
|
12
|
+
require 'smart_proxy_acd/acd_runner'
|
13
|
+
require 'smart_proxy_acd/acd_task_launcher'
|
14
|
+
end
|
15
|
+
|
16
|
+
default_settings :timeout => 60
|
17
|
+
|
18
|
+
load_dependency_injection_wirings do |_container_instance, _settings|
|
19
|
+
Proxy::Dynflow::TaskLauncherRegistry.register('acd', AcdTaskLauncher)
|
20
|
+
end
|
10
21
|
end
|
11
22
|
end
|
12
23
|
end
|
@@ -5,6 +5,17 @@ module Proxy
|
|
5
5
|
extend ::Proxy::Log
|
6
6
|
|
7
7
|
class << self
|
8
|
+
def plugin_settings
|
9
|
+
# rubocop:disable ClassVars
|
10
|
+
@@settings ||= OpenStruct.new(read_settings)
|
11
|
+
# rubocop:enable ClassVars
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_settings
|
15
|
+
::Proxy::Acd::Plugin.default_settings.merge(
|
16
|
+
YAML.load_file(File.join(::Proxy::SETTINGS.settings_directory, ::Proxy::Acd::Plugin.settings_file))
|
17
|
+
)
|
18
|
+
end
|
8
19
|
end
|
9
20
|
end
|
10
21
|
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'smart_proxy_dynflow/runner/base'
|
2
|
+
require 'smart_proxy_dynflow/runner/command_runner'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'rest-client'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'socket'
|
7
|
+
require 'proxy/request'
|
8
|
+
|
9
|
+
# rubocop:disable ClassLength
|
10
|
+
|
11
|
+
module Proxy
|
12
|
+
module Acd
|
13
|
+
# Implements the AcdRunner to be used by foreman_remote_execution
|
14
|
+
class AcdRunner < Proxy::Dynflow::Runner::CommandRunner
|
15
|
+
DEFAULT_REFRESH_INTERVAL = 1
|
16
|
+
|
17
|
+
def initialize(options, suspended_action:)
|
18
|
+
super(options, :suspended_action => suspended_action)
|
19
|
+
@options = options
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_playbook(playbook_id)
|
23
|
+
logger.debug("Get playbook with id #{playbook_id}")
|
24
|
+
response = playbook_resource(playbook_id)
|
25
|
+
if response.code.to_s != '200'
|
26
|
+
raise "Failed performing callback to Foreman server: #{response.code} #{response.body}"
|
27
|
+
end
|
28
|
+
tmp_file = Tempfile.new.path
|
29
|
+
File.write(tmp_file, response.body)
|
30
|
+
@playbook_tmp_base64_file = tmp_file
|
31
|
+
end
|
32
|
+
|
33
|
+
def playbook_resource(playbook_id)
|
34
|
+
playbook_download_path = "/acd/api/v2/ansible_playbooks/#{playbook_id}/grab"
|
35
|
+
foreman_request = Proxy::HttpRequest::ForemanRequest.new
|
36
|
+
req = foreman_request.request_factory.create_get(playbook_download_path)
|
37
|
+
foreman_request.http.read_timeout = Proxy::Acd::Plugin.settings.timeout
|
38
|
+
foreman_request.send_request(req)
|
39
|
+
end
|
40
|
+
|
41
|
+
def store_playbook
|
42
|
+
logger.debug('Unpack ansible playbook')
|
43
|
+
dir = Dir.mktmpdir
|
44
|
+
raise 'Could not create temporary directory to run ansible playbook' if dir.nil? || !Dir.exist?(dir)
|
45
|
+
command = "base64 -d #{@playbook_tmp_base64_file} | tar xz -C #{dir}"
|
46
|
+
system(command)
|
47
|
+
@playbook_tmp_dir = dir
|
48
|
+
end
|
49
|
+
|
50
|
+
def cleanup
|
51
|
+
File.unlink(@playbook_tmp_base64_file) if File.exist?(@playbook_tmp_base64_file)
|
52
|
+
FileUtils.rm_rf(@playbook_tmp_dir) if Dir.exist?(@playbook_tmp_dir)
|
53
|
+
end
|
54
|
+
|
55
|
+
def start
|
56
|
+
parse_acd_job
|
57
|
+
|
58
|
+
publish_data("Grab playbook to configure application #{@application_name}...", 'stdout')
|
59
|
+
get_playbook(@playbook_id)
|
60
|
+
store_playbook
|
61
|
+
|
62
|
+
@playbook_path = File.join(@playbook_tmp_dir, @playbook_file)
|
63
|
+
raise "Could not run playbook: playbook file #{@playbook_file} not found in playbook dir #{@playbook_tmp_dir}" unless File.exist?(@playbook_path)
|
64
|
+
|
65
|
+
publish_data('Write temporary inventory', 'stdout')
|
66
|
+
write_inventory
|
67
|
+
|
68
|
+
command = generate_command
|
69
|
+
logger.debug("Running command #{command.join(' ')}")
|
70
|
+
initialize_command(*command)
|
71
|
+
end
|
72
|
+
|
73
|
+
def close
|
74
|
+
logger.debug("Cleanup ansible playbook #{@playbook_tmp_dir} and #{@playbook_tmp_base64_file}")
|
75
|
+
cleanup
|
76
|
+
end
|
77
|
+
|
78
|
+
def kill
|
79
|
+
publish_data('== TASK ABORTED BY USER ==', 'stdout')
|
80
|
+
publish_exit_status(1)
|
81
|
+
::Process.kill('SIGTERM', @command_pid)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def parse_acd_job
|
87
|
+
@acd_job = YAML.safe_load(@options['script'])
|
88
|
+
@application_name = @acd_job['application_name']
|
89
|
+
@playbook_id = @acd_job['playbook_id']
|
90
|
+
@playbook_file = @acd_job['playbook_file']
|
91
|
+
|
92
|
+
raise "'playbook_file' need to be specified" if @playbook_file.nil? || @playbook_file.empty?
|
93
|
+
raise "'playbook_id' need to be specified" if @playbook_id.nil?
|
94
|
+
end
|
95
|
+
|
96
|
+
def proxy_hostname
|
97
|
+
Socket.gethostbyname(Socket.gethostname).first
|
98
|
+
end
|
99
|
+
|
100
|
+
def write_inventory
|
101
|
+
complete_inventory = YAML.safe_load(@acd_job['inventory'])
|
102
|
+
my_inventory = complete_inventory[proxy_hostname]
|
103
|
+
|
104
|
+
my_inventory['all']['children'].each_value do |group|
|
105
|
+
group['hosts'].each_value do |host_vars|
|
106
|
+
host_vars['ansible_ssh_private_key_file'] ||= Proxy::RemoteExecution::Ssh::Plugin.settings[:ssh_identity_key_file]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
tmp_inventory_file = Tempfile.new('acd_inventory')
|
111
|
+
tmp_inventory_file << my_inventory.to_yaml
|
112
|
+
tmp_inventory_file << "\n"
|
113
|
+
tmp_inventory_file.close
|
114
|
+
@inventory_path = tmp_inventory_file.path
|
115
|
+
end
|
116
|
+
|
117
|
+
def environment
|
118
|
+
env = {}
|
119
|
+
env['ANSIBLE_CALLBACK_WHITELIST'] = ''
|
120
|
+
env['ANSIBLE_LOAD_CALLBACK_PLUGINS'] = '0'
|
121
|
+
env
|
122
|
+
end
|
123
|
+
|
124
|
+
def setup_verbosity
|
125
|
+
verbosity = ''
|
126
|
+
if @acd_job['verbose']
|
127
|
+
verbosity_level = @acd_job['verbose'].split(' ').first.to_i
|
128
|
+
if verbosity_level.positive?
|
129
|
+
verbosity = '-'
|
130
|
+
verbosity_level.times do
|
131
|
+
verbosity += 'v'
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
verbosity
|
136
|
+
end
|
137
|
+
|
138
|
+
def valid_tags(tag)
|
139
|
+
re = /^\w+(\s*,\s*\w+)*$/
|
140
|
+
return true if @acd_job[tag] && @acd_job[tag].match?(re)
|
141
|
+
end
|
142
|
+
|
143
|
+
def generate_command
|
144
|
+
logger.debug("Generate command with #{@inventory_path} to run #{@playbook_id} with path #{@playbook_path}")
|
145
|
+
command = [environment]
|
146
|
+
command << 'ansible-playbook'
|
147
|
+
command << '-i'
|
148
|
+
command << @inventory_path
|
149
|
+
verbose = setup_verbosity
|
150
|
+
command << verbose unless verbose.empty?
|
151
|
+
command << "--tags '#{@acd_job['tags']}'" if valid_tags('tags')
|
152
|
+
command << "--skip-tags '#{@acd_job['skip_tags']}'" if valid_tags('skip_tags')
|
153
|
+
if @acd_job.key?('extra_vars') && !@acd_job['extra_vars'].nil? && !@acd_job['extra_vars'].empty?
|
154
|
+
command << '--extra-vars'
|
155
|
+
command << "'#{@acd_job['extra_vars']}'"
|
156
|
+
end
|
157
|
+
command << @playbook_path.to_s
|
158
|
+
command
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# rubocop:enable ClassLength
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'smart_proxy_dynflow/task_launcher'
|
2
|
+
|
3
|
+
module Proxy
|
4
|
+
module Acd
|
5
|
+
# Implements the TaskLauncher::Batch for Acd
|
6
|
+
class AcdTaskLauncher < Proxy::Dynflow::TaskLauncher::Batch
|
7
|
+
# Implements the Runner::Action for Acd
|
8
|
+
class AcdRunnerAction < Proxy::Dynflow::Action::Runner
|
9
|
+
def initiate_runner
|
10
|
+
additional_options = {
|
11
|
+
:step_id => run_step_id,
|
12
|
+
:uuid => execution_plan_id
|
13
|
+
}
|
14
|
+
::Proxy::Acd::AcdRunner.new(
|
15
|
+
input.merge(additional_options),
|
16
|
+
:suspended_action => suspended_action
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def child_launcher(parent)
|
22
|
+
Proxy::Dynflow::TaskLauncher::Single.new(world, callback, :parent => parent,
|
23
|
+
:action_class_override => AcdRunnerAction)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/settings.d/acd.yml.example
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_proxy_acd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Bucher
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.50.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: smart_proxy_dynflow
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.5.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.5.0
|
27
41
|
description: Application Centric Deployment smart proxy plugin
|
28
42
|
email: info@atix.de
|
29
43
|
executables: []
|
@@ -40,6 +54,8 @@ files:
|
|
40
54
|
- lib/smart_proxy_acd/acd_api.rb
|
41
55
|
- lib/smart_proxy_acd/acd_http_config.ru
|
42
56
|
- lib/smart_proxy_acd/acd_main.rb
|
57
|
+
- lib/smart_proxy_acd/acd_runner.rb
|
58
|
+
- lib/smart_proxy_acd/acd_task_launcher.rb
|
43
59
|
- lib/smart_proxy_acd/version.rb
|
44
60
|
- settings.d/acd.yml.example
|
45
61
|
homepage: http://github.com/ATIX-AG/smart_proxy_acd
|