aethernal-agent 0.1.10
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 +7 -0
- data/.gitignore +12 -0
- data/.gitlab-ci.yml +23 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +107 -0
- data/README.md +35 -0
- data/Rakefile +31 -0
- data/Vagrantfile +32 -0
- data/aethernal-agent.gemspec +45 -0
- data/bin/console +14 -0
- data/bin/run-aa-for-test +35 -0
- data/bin/setup +8 -0
- data/exe/aa-web +7 -0
- data/lib/aethernal_agent.rb +34 -0
- data/lib/aethernal_agent/apache/apache.rb +70 -0
- data/lib/aethernal_agent/apache/templates/aa-user.conf.erb +21 -0
- data/lib/aethernal_agent/app.rb +317 -0
- data/lib/aethernal_agent/apt.rb +30 -0
- data/lib/aethernal_agent/errors.rb +17 -0
- data/lib/aethernal_agent/filesystem.rb +178 -0
- data/lib/aethernal_agent/loader.rb +56 -0
- data/lib/aethernal_agent/manifest.rb +6 -0
- data/lib/aethernal_agent/operation.rb +51 -0
- data/lib/aethernal_agent/operation_pool.rb +46 -0
- data/lib/aethernal_agent/plugins/deluge/deluge.rb +65 -0
- data/lib/aethernal_agent/plugins/deluge/manifest.yml +51 -0
- data/lib/aethernal_agent/plugins/deluge/meta/deluge.png +0 -0
- data/lib/aethernal_agent/plugins/deluge/templates/auth.erb +2 -0
- data/lib/aethernal_agent/plugins/deluge/templates/core.conf.erb +95 -0
- data/lib/aethernal_agent/plugins/deluge/templates/deluge-web.service.erb +12 -0
- data/lib/aethernal_agent/plugins/deluge/templates/deluge.apache.conf.erb +9 -0
- data/lib/aethernal_agent/plugins/deluge/templates/deluged.service.erb +12 -0
- data/lib/aethernal_agent/plugins/deluge/templates/hostlist.conf.erb +14 -0
- data/lib/aethernal_agent/plugins/deluge/templates/web.conf.erb +24 -0
- data/lib/aethernal_agent/plugins/filebrowser/filebrowser.rb +45 -0
- data/lib/aethernal_agent/plugins/filebrowser/files/filebrowser.service +12 -0
- data/lib/aethernal_agent/plugins/filebrowser/manifest.yml +51 -0
- data/lib/aethernal_agent/plugins/filebrowser/meta/filebrowser.png +0 -0
- data/lib/aethernal_agent/plugins/filebrowser/templates/filebrowser.apache.conf.erb +6 -0
- data/lib/aethernal_agent/plugins/gitea/files/gitea.service +12 -0
- data/lib/aethernal_agent/plugins/gitea/gitea.rb +64 -0
- data/lib/aethernal_agent/plugins/gitea/manifest.yml +53 -0
- data/lib/aethernal_agent/plugins/gitea/meta/gitea.png +0 -0
- data/lib/aethernal_agent/plugins/gitea/templates/app.ini.erb +68 -0
- data/lib/aethernal_agent/plugins/gitea/templates/gitea.apache.conf.erb +6 -0
- data/lib/aethernal_agent/plugins/olaris/manifest.yml +52 -0
- data/lib/aethernal_agent/plugins/olaris/meta/olaris.png +0 -0
- data/lib/aethernal_agent/plugins/olaris/olaris.rb +35 -0
- data/lib/aethernal_agent/plugins/olaris/templates/olaris.apache.conf.erb +6 -0
- data/lib/aethernal_agent/plugins/olaris/templates/olaris.service.erb +12 -0
- data/lib/aethernal_agent/plugins/ombi/manifest.yml +57 -0
- data/lib/aethernal_agent/plugins/ombi/meta/ombi.jpeg +0 -0
- data/lib/aethernal_agent/plugins/ombi/ombi.rb +81 -0
- data/lib/aethernal_agent/plugins/ombi/templates/ombi.apache.conf.erb +6 -0
- data/lib/aethernal_agent/plugins/ombi/templates/ombi.service.erb +14 -0
- data/lib/aethernal_agent/plugins/plex/files/plex.service +26 -0
- data/lib/aethernal_agent/plugins/plex/manifest.yml +49 -0
- data/lib/aethernal_agent/plugins/plex/meta/plex.png +0 -0
- data/lib/aethernal_agent/plugins/plex/plex.rb +65 -0
- data/lib/aethernal_agent/plugins/plex/templates/Preferences.xml.erb +2 -0
- data/lib/aethernal_agent/plugins/radarr/files/radarr.service +13 -0
- data/lib/aethernal_agent/plugins/radarr/manifest.yml +68 -0
- data/lib/aethernal_agent/plugins/radarr/meta/radarr.png +0 -0
- data/lib/aethernal_agent/plugins/radarr/radarr.rb +72 -0
- data/lib/aethernal_agent/plugins/radarr/templates/config.xml.erb +16 -0
- data/lib/aethernal_agent/plugins/radarr/templates/radarr.apache.conf.erb +6 -0
- data/lib/aethernal_agent/plugins/sonarr/files/sonarr.service +13 -0
- data/lib/aethernal_agent/plugins/sonarr/manifest.yml +66 -0
- data/lib/aethernal_agent/plugins/sonarr/meta/sonarr.jpeg +0 -0
- data/lib/aethernal_agent/plugins/sonarr/sonarr.rb +70 -0
- data/lib/aethernal_agent/plugins/sonarr/templates/config.xml.erb +16 -0
- data/lib/aethernal_agent/plugins/sonarr/templates/sonarr.apache.conf.erb +6 -0
- data/lib/aethernal_agent/plugins/vnc/files/xstartup +9 -0
- data/lib/aethernal_agent/plugins/vnc/manifest.yml +41 -0
- data/lib/aethernal_agent/plugins/vnc/meta/vnc.png +0 -0
- data/lib/aethernal_agent/plugins/vnc/templates/vnc.service.erb +14 -0
- data/lib/aethernal_agent/plugins/vnc/vnc.rb +41 -0
- data/lib/aethernal_agent/systemd.rb +123 -0
- data/lib/aethernal_agent/template.rb +57 -0
- data/lib/aethernal_agent/utils.rb +107 -0
- data/lib/aethernal_agent/version.rb +3 -0
- data/lib/aethernal_agent/webserver/api.rb +77 -0
- data/lib/aethernal_agent/webserver/core.rb +32 -0
- metadata +257 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# AUTOMATICALLY GENERATED DON'T EDIT THIS FILE UNLESS YOU WANT TO SEE YOUR CHANGES DO _POOF_
|
|
2
|
+
# <%=DateTime.now %>
|
|
3
|
+
<VirtualHost *:80>
|
|
4
|
+
ServerName <%= @user %>.<%= @container_name %>.<%= @host_name %>
|
|
5
|
+
<% if @custom_domains.present? %>
|
|
6
|
+
<% @custom_domains.each do |domain| %>
|
|
7
|
+
ServerAlias <%= @user %>.<%= domain %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
DocumentRoot <%= @home_folder %>/www
|
|
12
|
+
CustomLog /var/log/apache2/<%= @user %>.base-access.log combined
|
|
13
|
+
ErrorLog /var/log/apache2/<%= @user %>.base-error.log
|
|
14
|
+
IncludeOptional users/<%= @user %>/*.conf
|
|
15
|
+
|
|
16
|
+
<Directory <%= @home_folder %>/www>
|
|
17
|
+
AllowOverride all
|
|
18
|
+
Require all granted
|
|
19
|
+
</Directory>
|
|
20
|
+
|
|
21
|
+
</VirtualHost>
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
require 'open-uri'
|
|
2
|
+
require 'aethernal_agent/apt'
|
|
3
|
+
require 'digest/sha1'
|
|
4
|
+
require 'aethernal_agent/filesystem'
|
|
5
|
+
require 'aethernal_agent/systemd'
|
|
6
|
+
require 'aethernal_agent/utils'
|
|
7
|
+
require 'aethernal_agent/errors'
|
|
8
|
+
require 'aethernal_agent/apache/apache'
|
|
9
|
+
require 'active_support'
|
|
10
|
+
require 'active_support/core_ext'
|
|
11
|
+
|
|
12
|
+
module AethernalAgent
|
|
13
|
+
class App
|
|
14
|
+
include AethernalAgent::Apt
|
|
15
|
+
include AethernalAgent::Filesystem
|
|
16
|
+
include AethernalAgent::Systemd
|
|
17
|
+
include AethernalAgent::Utils
|
|
18
|
+
include AethernalAgent::Errors
|
|
19
|
+
|
|
20
|
+
attr_accessor :manifest, :user, :plugin_path, :global_options
|
|
21
|
+
|
|
22
|
+
def initialize(options = {})
|
|
23
|
+
options = HashWithIndifferentAccess.new(options)
|
|
24
|
+
self.global_options = options
|
|
25
|
+
self.plugin_path = options[:file_path] || caller_locations(0)[1].path
|
|
26
|
+
self.user = options[:user]
|
|
27
|
+
|
|
28
|
+
AethernalAgent.logger.debug("initializing plugin from #{plugin_path}")
|
|
29
|
+
self.manifest = OpenStruct.new(YAML.load_file(File.join(File.dirname(self.plugin_path), "manifest.yml")))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#FIXME: Add error tracking
|
|
33
|
+
def install_packages(options = {})
|
|
34
|
+
directory(home_folder_path("/.config"), owner: self.user)
|
|
35
|
+
AethernalAgent.logger.info("Installing packages for #{self.manifest.name} - v#{self.manifest.version}")
|
|
36
|
+
|
|
37
|
+
if self.manifest.package.has_key?('ppa')
|
|
38
|
+
self.manifest.package['ppa'].each do |ppa|
|
|
39
|
+
AethernalAgent.logger.debug("Setting up PPA: #{ppa}")
|
|
40
|
+
run_command("add-apt-repository ppa:#{ppa} -y")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
self.manifest.package.each_key do |package_type|
|
|
45
|
+
case package_type
|
|
46
|
+
when 'apt'
|
|
47
|
+
options = self.manifest.package['apt'][ubuntu_release]
|
|
48
|
+
AethernalAgent.logger.debug("Using apt for ubuntu #{ubuntu_release} - #{options}")
|
|
49
|
+
packages = options['packages']
|
|
50
|
+
|
|
51
|
+
if options.has_key?('add_sources')
|
|
52
|
+
AethernalAgent.logger.debug("Adding custom sources")
|
|
53
|
+
options['add_sources'].each do |name, source|
|
|
54
|
+
AethernalAgent.logger.debug("Setting up custom apt source '#{name}'")
|
|
55
|
+
file_path = "/etc/apt/sources.list.d/#{name}.list"
|
|
56
|
+
|
|
57
|
+
unless File.exist?(file_path)
|
|
58
|
+
run_command("echo '#{source['source_url']}' > #{file_path}")
|
|
59
|
+
else
|
|
60
|
+
AethernalAgent.logger.debug("Custom apt source '#{name}' already present, not rewriting.")
|
|
61
|
+
end
|
|
62
|
+
run_command("curl #{source['key_url']} | sudo apt-key add -") if source['key_url'].present?
|
|
63
|
+
run_command("sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys #{source['key_id']}") if source['key_id'].present?
|
|
64
|
+
end
|
|
65
|
+
apt_update
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if packages
|
|
69
|
+
AethernalAgent.logger.debug("Installing packages #{packages}")
|
|
70
|
+
apt_package(packages: packages)
|
|
71
|
+
end
|
|
72
|
+
when 'direct_download'
|
|
73
|
+
opts = self.manifest.package[package_type]
|
|
74
|
+
target_file = File.join(app_path, opts["target_name"])
|
|
75
|
+
directory(app_path, owner: self.user)
|
|
76
|
+
AethernalAgent.logger.debug("Downloading file from '#{opts["url"]}' to '#{target_file}'")
|
|
77
|
+
File.open(target_file, "wb") do |saved_file|
|
|
78
|
+
open(opts["url"], "rb") do |read_file|
|
|
79
|
+
saved_file.write(read_file.read)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
if opts["auto_unzip"]
|
|
84
|
+
unzip(opts["target_name"], delete_after: true)
|
|
85
|
+
elsif opts["auto_extract"]
|
|
86
|
+
extract(opts["target_name"], delete_after: true)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
AethernalAgent.logger.info("Done Installing packages for #{self.manifest.name} - v#{self.manifest.version}")
|
|
91
|
+
return create_return_args(options)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def uninstall_packages(options = {})
|
|
95
|
+
AethernalAgent.logger.info("Uninstalling packages for #{self.manifest.name} - v#{self.manifest.version}")
|
|
96
|
+
|
|
97
|
+
self.stop
|
|
98
|
+
self.disable
|
|
99
|
+
|
|
100
|
+
self.manifest.package.each_key do |package_type|
|
|
101
|
+
case package_type
|
|
102
|
+
when "apt"
|
|
103
|
+
AethernalAgent.logger.debug("Using apt for ubuntu #{ubuntu_release}")
|
|
104
|
+
packages = self.manifest.package[package_type][ubuntu_release]
|
|
105
|
+
AethernalAgent.logger.debug("Removing packages #{packages}")
|
|
106
|
+
apt_package(packages: packages, action: :remove) if packages
|
|
107
|
+
when "direct_download"
|
|
108
|
+
directory(app_path, action: :delete)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
return create_return_args(options)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def configure_app_user(options={})
|
|
116
|
+
errors = {}
|
|
117
|
+
opts, errors = ensure_action_options(__method__,options)
|
|
118
|
+
return {errors: errors} unless errors.empty?
|
|
119
|
+
|
|
120
|
+
if self.manifest.apache_configuration
|
|
121
|
+
apache = AethernalAgent::Apache.new(opts)
|
|
122
|
+
errors = apache.ensure_base_config(opts)
|
|
123
|
+
apache.write_app_config(template_path(self.manifest.apache_configuration), self.manifest.plain_name, opts[:port])
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
AethernalAgent.logger.debug("Running custom plugin code.")
|
|
127
|
+
yield opts if block_given?
|
|
128
|
+
AethernalAgent.logger.debug("Done running custom plugin code.")
|
|
129
|
+
|
|
130
|
+
AethernalAgent.logger.debug("Starting service generation.")
|
|
131
|
+
self.manifest.services.each do |s|
|
|
132
|
+
options = {service_name: "#{s}.service", user: self.user, vars: opts}
|
|
133
|
+
service_template = template_path("#{s}.service.erb")
|
|
134
|
+
if File.exists?(service_template)
|
|
135
|
+
AethernalAgent.logger.debug("Found service template")
|
|
136
|
+
options[:template] = "#{s}.service.erb"
|
|
137
|
+
elsif File.exists?(files_path("#{s}.service"))
|
|
138
|
+
AethernalAgent.logger.debug("Found service file")
|
|
139
|
+
options[:file] = "#{s}.service"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
create_service_file(options)
|
|
143
|
+
end
|
|
144
|
+
AethernalAgent.logger.debug("Done with service generation.")
|
|
145
|
+
|
|
146
|
+
directory(home_folder_path("apps"), owner: self.user)
|
|
147
|
+
|
|
148
|
+
AethernalAgent.logger.debug("Done running configure_app_user")
|
|
149
|
+
return create_return_args(opts)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def remove_app_user(options={})
|
|
153
|
+
opts, errors = ensure_action_options(__method__,options)
|
|
154
|
+
return {errors: errors} unless errors.empty?
|
|
155
|
+
|
|
156
|
+
run_user_systemctl(:stop)
|
|
157
|
+
|
|
158
|
+
self.manifest.services.each do |service|
|
|
159
|
+
file(service_file_path("#{service}.service"), action: :delete)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
if self.manifest.apache_configuration
|
|
163
|
+
apache = AethernalAgent::Apache.new(opts)
|
|
164
|
+
apache.remove_app_config(self.manifest.plain_name)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
if self.is_local_install?
|
|
168
|
+
self.uninstall_packages(opts)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
yield opts if block_given?
|
|
172
|
+
|
|
173
|
+
return create_return_args(opts)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def create_return_args(options)
|
|
177
|
+
res = {options: options, errors: get_errors}
|
|
178
|
+
|
|
179
|
+
if options[:errors].present?
|
|
180
|
+
res[:errors] << options.slice(:errors)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
return res
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def status(options = {})
|
|
187
|
+
if options[:service_name]
|
|
188
|
+
status = get_systemd_status(options[:service_name])
|
|
189
|
+
return status.to_h if status
|
|
190
|
+
else
|
|
191
|
+
stati = self.manifest.services.collect do |service|
|
|
192
|
+
status = get_systemd_status(service)
|
|
193
|
+
status.to_h if status
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
return stati
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def ensure_action_options(method_name, options={})
|
|
201
|
+
options = HashWithIndifferentAccess.new(options.reverse_merge(global_options))
|
|
202
|
+
|
|
203
|
+
errors = {}
|
|
204
|
+
AethernalAgent.logger.debug "Running '#{method_name}' with options '#{options}'"
|
|
205
|
+
if self.manifest.actions.keys.include?(method_name.to_s)
|
|
206
|
+
opts = self.manifest.actions[method_name.to_s]
|
|
207
|
+
opts.each do |opt, reqs|
|
|
208
|
+
AethernalAgent.logger.debug "Checking option #{opt} - requirements: #{reqs}"
|
|
209
|
+
|
|
210
|
+
next if reqs.blank?
|
|
211
|
+
|
|
212
|
+
# The option is required but has not been supplied
|
|
213
|
+
if reqs.include?("required") && reqs["required"] == true
|
|
214
|
+
AethernalAgent.logger.debug("#{opt} is required")
|
|
215
|
+
if options.has_key?(opt) && !options[opt].blank?
|
|
216
|
+
AethernalAgent.logger.debug("required option is supplied")
|
|
217
|
+
else
|
|
218
|
+
AethernalAgent.logger.debug("required option is not supplied")
|
|
219
|
+
errors[opt] ||= []
|
|
220
|
+
errors[opt] << "is required but has not been supplied"
|
|
221
|
+
next
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# This option should be an autogenerated string (passwords)
|
|
226
|
+
if reqs.include?("auto_generate") && reqs["auto_generate"] == true && (!options.has_key?(opt) || options[opt].empty?)
|
|
227
|
+
options[opt] = self.random_string
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# This option should be an autogenerated port
|
|
231
|
+
if reqs.include?("auto_generate_port") && reqs["auto_generate_port"] == true && (!options.has_key?(opt) || options[opt].blank?)
|
|
232
|
+
min = reqs["min"] || 2000
|
|
233
|
+
max = reqs["max"] || 8000
|
|
234
|
+
options[opt] = random_port(min..max)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# The option should be a linux_user
|
|
238
|
+
if reqs.include?("linux_user") && reqs["linux_user"] == true
|
|
239
|
+
AethernalAgent.logger.debug "Checking to see if '#{options[:user]}' is a local linux user."
|
|
240
|
+
begin
|
|
241
|
+
Etc.getpwnam(options[:user])
|
|
242
|
+
rescue ArgumentError => e
|
|
243
|
+
errors[opt] ||= []
|
|
244
|
+
errors[opt] << e.to_s
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
else
|
|
249
|
+
puts "Method '#{method_name}' not defined in manifest."
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
return options, errors
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def app_path(path=nil)
|
|
256
|
+
full_path = home_folder_path(File.join("apps", self.manifest.package['folder_name']))
|
|
257
|
+
if path
|
|
258
|
+
return File.join(full_path, path)
|
|
259
|
+
else
|
|
260
|
+
return full_path
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def icon_sha
|
|
265
|
+
if self.manifest.icon.present?
|
|
266
|
+
return self.manifest.icon["sha256sum"]
|
|
267
|
+
else
|
|
268
|
+
return ""
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def icon_file(path=nil)
|
|
273
|
+
if self.manifest.icon.present?
|
|
274
|
+
icon_path = meta_path(self.manifest.icon['name'])
|
|
275
|
+
if File.exist?(icon_path)
|
|
276
|
+
return Base64.encode64(File.read(icon_path))
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
return nil
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def extract(source_file, options = {})
|
|
284
|
+
options.reverse_merge!(extract_to_path: self.app_path, source_folder: self.app_path, auto_detect: true, extract_as: File.extname(source_file))
|
|
285
|
+
|
|
286
|
+
extract_from = File.join(options[:source_folder], source_file)
|
|
287
|
+
extract_to = options[:extract_to_path]
|
|
288
|
+
|
|
289
|
+
case options[:extract_as].gsub('.', '')
|
|
290
|
+
when "gz", "tar"
|
|
291
|
+
run_command("tar -C #{extract_to} -xvf #{extract_from}")
|
|
292
|
+
when "zip"
|
|
293
|
+
run_command("unzip -od #{extract_to} #{extract_from}")
|
|
294
|
+
else
|
|
295
|
+
raise "#{options[:extract_as]} not implemented yet"
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
file(extract_from, action: :delete) if options[:delete_after]
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def unzip(source_file)
|
|
302
|
+
extract(source_file, extract_as: "zip")
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def is_local_install?
|
|
306
|
+
self.manifest.installation_type == 'local_install'
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def sha_1_hash(password, salt)
|
|
310
|
+
sha = Digest::SHA1.new
|
|
311
|
+
sha.update(salt)
|
|
312
|
+
sha.update(password)
|
|
313
|
+
|
|
314
|
+
return sha.hexdigest
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module AethernalAgent
|
|
2
|
+
module Apt
|
|
3
|
+
def apt_update
|
|
4
|
+
system("apt update")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def add_apt_ppa(name)
|
|
8
|
+
system("add-apt-repository #{name} -y")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def apt_package(options = {})
|
|
12
|
+
action = options[:action]
|
|
13
|
+
action = :install if action.nil?
|
|
14
|
+
|
|
15
|
+
packages = options[:packages]
|
|
16
|
+
packages = packages.join(" ") if packages.is_a?(Array)
|
|
17
|
+
|
|
18
|
+
case action
|
|
19
|
+
when :install
|
|
20
|
+
# Do this with popen so we can catch error output as well as normal output for add_errors
|
|
21
|
+
system("DEBIAN_FRONTEND=noninteractive apt -o DPkg::Options::=--force-confdef install -qy #{packages}")
|
|
22
|
+
when :remove
|
|
23
|
+
system("DEBIAN_FRONTEND=noninteractive apt remove -qy #{packages}")
|
|
24
|
+
system("DEBIAN_FRONTEND=noninteractive apt autoremove -qy")
|
|
25
|
+
when :autoremove
|
|
26
|
+
system("DEBIAN_FRONTEND=noninteractive apt autoremove -qy")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module AethernalAgent
|
|
2
|
+
module Errors
|
|
3
|
+
attr_accessor :global_errors
|
|
4
|
+
|
|
5
|
+
def add_errors(error, vars = {})
|
|
6
|
+
AethernalAgent.logger.debug("Adding errors: '#{error}'")
|
|
7
|
+
self.global_errors ||=[]
|
|
8
|
+
self.global_errors << {method: caller_locations(2,1)[0].label, error: error, args: vars}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def get_errors
|
|
12
|
+
errors = self.global_errors
|
|
13
|
+
self.global_errors = []
|
|
14
|
+
return errors
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
module AethernalAgent
|
|
2
|
+
module Filesystem
|
|
3
|
+
def files_folder
|
|
4
|
+
File.join(File.expand_path(File.dirname(plugin_path)), "files/")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def files_path(file)
|
|
8
|
+
File.join(files_folder, file)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def meta_folder
|
|
12
|
+
File.join(File.expand_path(File.dirname(plugin_path)), "meta/")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def meta_path(file)
|
|
16
|
+
File.join(meta_folder, file)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def templates_folder
|
|
20
|
+
File.join(File.expand_path(File.dirname(plugin_path)), "templates/")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def template_path(file)
|
|
24
|
+
File.join(templates_folder, file)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def home_folder_path(path = nil)
|
|
28
|
+
if !path.nil?
|
|
29
|
+
File.join(Dir.home(self.user), path)
|
|
30
|
+
else
|
|
31
|
+
File.join(Dir.home(self.user))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def set_ownership(path, user, group=nil)
|
|
36
|
+
AethernalAgent.logger.debug("Setting ownership of '#{path}' to user '#{user}'")
|
|
37
|
+
begin
|
|
38
|
+
FileUtils.chown_R(user,group,path)
|
|
39
|
+
rescue SystemCallError => e
|
|
40
|
+
add_errors(e, path: path, user:user, group: group)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def set_permissions(path, chmod)
|
|
45
|
+
AethernalAgent.logger.debug("Setting chmod of '#{path}' to chmod '#{chmod}'")
|
|
46
|
+
begin
|
|
47
|
+
FileUtils.chmod(chmod, path)
|
|
48
|
+
rescue SystemCallError => e
|
|
49
|
+
add_errors(e, path: path, chmod: chmod)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def file_settings(file_path, options = {})
|
|
54
|
+
AethernalAgent.logger.debug "Setting file settings with options: #{options}"
|
|
55
|
+
set_permissions(file_path, options[:chmod]) if options[:chmod]
|
|
56
|
+
set_ownership(file_path, options[:owner]) if options[:owner]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def file(file_path, options = {})
|
|
60
|
+
options.reverse_merge!(action: :create)
|
|
61
|
+
|
|
62
|
+
AethernalAgent.logger.debug "Applying action #{options[:action]} on file '#{file_path}'."
|
|
63
|
+
|
|
64
|
+
if options[:action] == :delete
|
|
65
|
+
if File.directory?(file_path)
|
|
66
|
+
add_errors("File is directory, not going to remove it with file() method.", path: file_path)
|
|
67
|
+
elsif File.exist?(file_path)
|
|
68
|
+
begin
|
|
69
|
+
FileUtils.rm(file_path)
|
|
70
|
+
rescue SystemCallError => e
|
|
71
|
+
add_errors(e, path: file_path)
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
add_errors("File does not exist.", path: file_path)
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
set_ownership(file_path, options[:owner]) if options[:owner]
|
|
78
|
+
set_permissions(file_path, options[:chmod]) if options[:chmod]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def copy(source, target, options = {})
|
|
83
|
+
AethernalAgent.logger.debug "Applying action #{options[:action]} on file or directory '#{source}'."
|
|
84
|
+
if source.present? && target.present?
|
|
85
|
+
if File.directory?(source) || File.exist?(source)
|
|
86
|
+
if File.exists?(target)
|
|
87
|
+
add_errors("File or folder already exists.", path: target)
|
|
88
|
+
else
|
|
89
|
+
begin
|
|
90
|
+
if File.directory?(source)
|
|
91
|
+
FileUtils.cp_r(source, target)
|
|
92
|
+
else
|
|
93
|
+
FileUtils.cp(source, target)
|
|
94
|
+
end
|
|
95
|
+
rescue SystemCallError => e
|
|
96
|
+
add_errors(e, path: file_path)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
else
|
|
100
|
+
add_errors("File or folder does not exist.", path: source)
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
add_errors("Source or destination are missing.")
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def directory(path, options = {})
|
|
108
|
+
options.reverse_merge!(action: :create)
|
|
109
|
+
|
|
110
|
+
AethernalAgent.logger.debug "Applying action #{options[:action]} on directory '#{path}'."
|
|
111
|
+
if options[:action] == :create
|
|
112
|
+
unless File.directory?(path)
|
|
113
|
+
begin
|
|
114
|
+
FileUtils.mkdir_p(path)
|
|
115
|
+
rescue Errno::EEXIST, Errno::EACCES => e
|
|
116
|
+
add_errors(e, path: path)
|
|
117
|
+
return
|
|
118
|
+
end
|
|
119
|
+
else
|
|
120
|
+
AethernalAgent.logger.debug "#{path} folder already exist, not creating."
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
set_ownership(path, options[:owner]) if options[:owner]
|
|
124
|
+
set_permissions(path, options[:chmod]) if options[:chmod]
|
|
125
|
+
elsif options[:action] == :delete
|
|
126
|
+
if File.directory?(path)
|
|
127
|
+
begin
|
|
128
|
+
FileUtils.rm_r(path)
|
|
129
|
+
rescue Errno::EACCES => e
|
|
130
|
+
add_errors(e, path: path)
|
|
131
|
+
end
|
|
132
|
+
else
|
|
133
|
+
AethernalAgent.logger.debug "#{path} does not exist, not removing."
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
return true
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def aethernal_agent_folder
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def aethernal_agent_file(source_file, target_file_path, options = {})
|
|
144
|
+
AethernalAgent.logger.debug("Attempting to copy file '#{source_file}' to '#{target_file_path}'")
|
|
145
|
+
|
|
146
|
+
if File.exists?(target_file_path)
|
|
147
|
+
AethernalAgent.logger.debug("File already exists, not copying.")
|
|
148
|
+
else
|
|
149
|
+
begin
|
|
150
|
+
FileUtils.cp(File.join(files_folder,source_file), target_file_path)
|
|
151
|
+
rescue SystemCallError => e
|
|
152
|
+
AethernalAgent.logger.debug("'#{source_file}' could not be created, giving up. Error: '#{e}'")
|
|
153
|
+
add_errors(e,source_file: source_file, target_file_path: target_file_path)
|
|
154
|
+
return false
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
set_permissions(target_file_path, options[:chmod]) if options[:chmod]
|
|
159
|
+
set_ownership(target_file_path, options[:owner]) if options[:owner]
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def write_template(in_path, out_path, vars, options={})
|
|
163
|
+
out_folder = File.dirname(out_path)
|
|
164
|
+
unless Dir.exist?(out_folder)
|
|
165
|
+
FileUtils.mkdir_p(out_folder)
|
|
166
|
+
set_permissions(out_folder, options[:chmod]) if options[:chmod]
|
|
167
|
+
set_ownership(out_folder, options[:owner]) if options[:owner]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
AethernalAgent.logger.debug("Writing template '#{in_path}' to '#{out_path}'")
|
|
171
|
+
template = AethernalAgent::Template.new(in_path,vars, options)
|
|
172
|
+
|
|
173
|
+
if template.parse
|
|
174
|
+
return template.write_to(out_path)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|