aethernal-agent 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.gitlab-ci.yml +23 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +107 -0
  9. data/README.md +35 -0
  10. data/Rakefile +31 -0
  11. data/Vagrantfile +32 -0
  12. data/aethernal-agent.gemspec +45 -0
  13. data/bin/console +14 -0
  14. data/bin/run-aa-for-test +35 -0
  15. data/bin/setup +8 -0
  16. data/exe/aa-web +7 -0
  17. data/lib/aethernal_agent.rb +34 -0
  18. data/lib/aethernal_agent/apache/apache.rb +70 -0
  19. data/lib/aethernal_agent/apache/templates/aa-user.conf.erb +21 -0
  20. data/lib/aethernal_agent/app.rb +317 -0
  21. data/lib/aethernal_agent/apt.rb +30 -0
  22. data/lib/aethernal_agent/errors.rb +17 -0
  23. data/lib/aethernal_agent/filesystem.rb +178 -0
  24. data/lib/aethernal_agent/loader.rb +56 -0
  25. data/lib/aethernal_agent/manifest.rb +6 -0
  26. data/lib/aethernal_agent/operation.rb +51 -0
  27. data/lib/aethernal_agent/operation_pool.rb +46 -0
  28. data/lib/aethernal_agent/plugins/deluge/deluge.rb +65 -0
  29. data/lib/aethernal_agent/plugins/deluge/manifest.yml +51 -0
  30. data/lib/aethernal_agent/plugins/deluge/meta/deluge.png +0 -0
  31. data/lib/aethernal_agent/plugins/deluge/templates/auth.erb +2 -0
  32. data/lib/aethernal_agent/plugins/deluge/templates/core.conf.erb +95 -0
  33. data/lib/aethernal_agent/plugins/deluge/templates/deluge-web.service.erb +12 -0
  34. data/lib/aethernal_agent/plugins/deluge/templates/deluge.apache.conf.erb +9 -0
  35. data/lib/aethernal_agent/plugins/deluge/templates/deluged.service.erb +12 -0
  36. data/lib/aethernal_agent/plugins/deluge/templates/hostlist.conf.erb +14 -0
  37. data/lib/aethernal_agent/plugins/deluge/templates/web.conf.erb +24 -0
  38. data/lib/aethernal_agent/plugins/filebrowser/filebrowser.rb +45 -0
  39. data/lib/aethernal_agent/plugins/filebrowser/files/filebrowser.service +12 -0
  40. data/lib/aethernal_agent/plugins/filebrowser/manifest.yml +51 -0
  41. data/lib/aethernal_agent/plugins/filebrowser/meta/filebrowser.png +0 -0
  42. data/lib/aethernal_agent/plugins/filebrowser/templates/filebrowser.apache.conf.erb +6 -0
  43. data/lib/aethernal_agent/plugins/gitea/files/gitea.service +12 -0
  44. data/lib/aethernal_agent/plugins/gitea/gitea.rb +64 -0
  45. data/lib/aethernal_agent/plugins/gitea/manifest.yml +53 -0
  46. data/lib/aethernal_agent/plugins/gitea/meta/gitea.png +0 -0
  47. data/lib/aethernal_agent/plugins/gitea/templates/app.ini.erb +68 -0
  48. data/lib/aethernal_agent/plugins/gitea/templates/gitea.apache.conf.erb +6 -0
  49. data/lib/aethernal_agent/plugins/olaris/manifest.yml +52 -0
  50. data/lib/aethernal_agent/plugins/olaris/meta/olaris.png +0 -0
  51. data/lib/aethernal_agent/plugins/olaris/olaris.rb +35 -0
  52. data/lib/aethernal_agent/plugins/olaris/templates/olaris.apache.conf.erb +6 -0
  53. data/lib/aethernal_agent/plugins/olaris/templates/olaris.service.erb +12 -0
  54. data/lib/aethernal_agent/plugins/ombi/manifest.yml +57 -0
  55. data/lib/aethernal_agent/plugins/ombi/meta/ombi.jpeg +0 -0
  56. data/lib/aethernal_agent/plugins/ombi/ombi.rb +81 -0
  57. data/lib/aethernal_agent/plugins/ombi/templates/ombi.apache.conf.erb +6 -0
  58. data/lib/aethernal_agent/plugins/ombi/templates/ombi.service.erb +14 -0
  59. data/lib/aethernal_agent/plugins/plex/files/plex.service +26 -0
  60. data/lib/aethernal_agent/plugins/plex/manifest.yml +49 -0
  61. data/lib/aethernal_agent/plugins/plex/meta/plex.png +0 -0
  62. data/lib/aethernal_agent/plugins/plex/plex.rb +65 -0
  63. data/lib/aethernal_agent/plugins/plex/templates/Preferences.xml.erb +2 -0
  64. data/lib/aethernal_agent/plugins/radarr/files/radarr.service +13 -0
  65. data/lib/aethernal_agent/plugins/radarr/manifest.yml +68 -0
  66. data/lib/aethernal_agent/plugins/radarr/meta/radarr.png +0 -0
  67. data/lib/aethernal_agent/plugins/radarr/radarr.rb +72 -0
  68. data/lib/aethernal_agent/plugins/radarr/templates/config.xml.erb +16 -0
  69. data/lib/aethernal_agent/plugins/radarr/templates/radarr.apache.conf.erb +6 -0
  70. data/lib/aethernal_agent/plugins/sonarr/files/sonarr.service +13 -0
  71. data/lib/aethernal_agent/plugins/sonarr/manifest.yml +66 -0
  72. data/lib/aethernal_agent/plugins/sonarr/meta/sonarr.jpeg +0 -0
  73. data/lib/aethernal_agent/plugins/sonarr/sonarr.rb +70 -0
  74. data/lib/aethernal_agent/plugins/sonarr/templates/config.xml.erb +16 -0
  75. data/lib/aethernal_agent/plugins/sonarr/templates/sonarr.apache.conf.erb +6 -0
  76. data/lib/aethernal_agent/plugins/vnc/files/xstartup +9 -0
  77. data/lib/aethernal_agent/plugins/vnc/manifest.yml +41 -0
  78. data/lib/aethernal_agent/plugins/vnc/meta/vnc.png +0 -0
  79. data/lib/aethernal_agent/plugins/vnc/templates/vnc.service.erb +14 -0
  80. data/lib/aethernal_agent/plugins/vnc/vnc.rb +41 -0
  81. data/lib/aethernal_agent/systemd.rb +123 -0
  82. data/lib/aethernal_agent/template.rb +57 -0
  83. data/lib/aethernal_agent/utils.rb +107 -0
  84. data/lib/aethernal_agent/version.rb +3 -0
  85. data/lib/aethernal_agent/webserver/api.rb +77 -0
  86. data/lib/aethernal_agent/webserver/core.rb +32 -0
  87. metadata +257 -0
@@ -0,0 +1,16 @@
1
+ <Config>
2
+ <Port><%= @port %></Port>
3
+ <UrlBase>/radarr</UrlBase>
4
+ <BindAddress>*</BindAddress>
5
+ <SslPort><%= @ssl_port %></SslPort>
6
+ <EnableSsl>False</EnableSsl>
7
+ <ApiKey><%= @api_key %></ApiKey>
8
+ <AuthenticationMethod>Forms</AuthenticationMethod>
9
+ <LogLevel>Info</LogLevel>
10
+ <LaunchBrowser>False</LaunchBrowser>
11
+ <Branch>develop</Branch>
12
+ <SslCertHash>
13
+ </SslCertHash>
14
+ <UpdateMechanism>BuiltIn</UpdateMechanism>
15
+ <UpdateAutomatically>True</UpdateAutomatically>
16
+ </Config>
@@ -0,0 +1,6 @@
1
+ Redirect "/radarr" "/radarr/app"
2
+ <Location /radarr/>
3
+ ProxyPass http://localhost:<%= @port %>
4
+ ProxyPassReverse http://localhost:<%= @port %>
5
+ Require all granted
6
+ </Location>
@@ -0,0 +1,13 @@
1
+ [Unit]
2
+ Description=Sonarr Daemon
3
+ After=syslog.target network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ ExecStart=/usr/bin/mono --debug %h/apps/sonarr/Sonarr.exe -nobrowser
8
+ TimeoutStopSec=20
9
+ KillMode=process
10
+ Restart=on-failure
11
+
12
+ [Install]
13
+ WantedBy=multi-user.target
@@ -0,0 +1,66 @@
1
+ name: Sonarr
2
+ script_name: sonarr.rb
3
+ version: 0.1
4
+ required_aethernal_agent_version: "~> 0.1.0"
5
+ description: Sonarr is a PVR for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.
6
+ installation_type: local_install
7
+ configuration_type: multi_user
8
+ apache_configuration: sonarr.apache.conf.erb
9
+ icon:
10
+ name: sonarr.jpeg
11
+ sha256sum: 325f7b0e6fff416105d8a23848bfe3e424d19505db6b2baf0d6740acb92d56d5
12
+ plain_name: sonarr
13
+ services:
14
+ - sonarr
15
+ actions:
16
+ restart:
17
+ user:
18
+ required: true
19
+ linux_user: true
20
+ uninstall:
21
+ nothing: true
22
+ install_packages:
23
+ user:
24
+ required: true
25
+ linux_user: true
26
+ remove_app_user:
27
+ user:
28
+ required: true
29
+ linux_user: true
30
+ configure_app_user:
31
+ port:
32
+ auto_generate_port: true
33
+ min: 6900
34
+ max: 6999
35
+ ssl_port:
36
+ auto_generate_port: true
37
+ min: 7900
38
+ max: 7999
39
+ user:
40
+ required: true
41
+ linux_user: true
42
+ password:
43
+ required: false
44
+ auto_generate: true
45
+ return_values:
46
+ - password
47
+ - port
48
+ display_values:
49
+ - user
50
+ - password
51
+ estimated_size_mb: 23
52
+ package:
53
+ folder_name: Sonarr
54
+ direct_download:
55
+ url: http://download.sonarr.tv/v3/phantom-develop/3.0.3.731/Sonarr.phantom-develop.3.0.3.731.linux.tar.gz
56
+ target_name: Sonarr.phantom-develop.3.0.3.731.linux.tar.gz
57
+ auto_extract: true
58
+ always_latest: false
59
+ apt:
60
+ "18.04":
61
+ add_sources:
62
+ mono_stable:
63
+ source_url: "deb https://download.mono-project.com/repo/ubuntu stable-bionic main"
64
+ key_id: "3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF"
65
+ packages:
66
+ - mono-devel
@@ -0,0 +1,70 @@
1
+ class AethernalAgent::Sonarr < AethernalAgent::App
2
+ def initialize(options = {})
3
+ super(options)
4
+ end
5
+
6
+ def install_packages(options = {})
7
+ remove_app_user
8
+
9
+ super(options)
10
+ file(app_path, chmod: 711, owner: self.user)
11
+ FileUtils.mv(app_path + "/Sonarr", app_path + "/sonarr")
12
+ FileUtils.mv(app_path + "/sonarr", home_folder_path(File.join("apps")))
13
+ directory(app_path, action: :delete)
14
+ end
15
+
16
+ def remove_app_user(options = {})
17
+ super(options) do |opts|
18
+ directory(home_folder_path("/apps/sonarr"), action: :delete)
19
+ directory(home_folder_path("/apps/Sonarr"), action: :delete)
20
+ directory(home_folder_path("/.config/Sonarr"), action: :delete)
21
+ end
22
+ end
23
+
24
+ def configure_app_user(options = {})
25
+ self.install_packages(options)
26
+ super(options) do |opts|
27
+ @vars = {
28
+ api_key: Digest::SHA256.hexdigest(Time.now.to_i.to_s + "aethernal")[0..32],
29
+ port: opts['port'],
30
+ ssl_port: opts['ssl_port'],
31
+ password: opts['password'],
32
+ user: self.user}
33
+
34
+ write_template(template_path('config.xml.erb'),
35
+ sonarr_config_path('config.xml'),
36
+ @vars,
37
+ {owner: @vars[:user]})
38
+ end
39
+ # If we run this within the super we have no systemd scripts yet so we need to do this after everything has been setup except the user.
40
+ add_user_to_db
41
+ return create_return_args(@vars)
42
+ end
43
+
44
+ protected
45
+
46
+ def sonarr_config_path(path ="/")
47
+ File.join(home_folder_path(".config/Sonarr"), path)
48
+ end
49
+
50
+ def add_user_to_db
51
+ # We need to start it for the database and migrations to be created
52
+ start
53
+ # Let's sleep a bit so we have some guarantee that the database has been migrated properly
54
+ sleep 120
55
+ # Let's stop it so we can mess with the database, not sure this is needed
56
+ stop
57
+ begin
58
+ db = SQLite3::Database.open(home_folder_path(".config/Sonarr/sonarr.db"))
59
+ # Add default user
60
+ db.execute "INSERT INTO Users VALUES (1, 'e852a6bb-6812-4e6c-8f99-f8c3c5201594', '#{self.user}', '#{Digest::SHA256.hexdigest(@vars[:password])}');"
61
+ rescue SQLite3::Exception => e
62
+ raise "Error setting up Sonarr: #{e}"
63
+ ensure
64
+ db.close if db
65
+ end
66
+
67
+ start
68
+ end
69
+
70
+ end
@@ -0,0 +1,16 @@
1
+ <Config>
2
+ <Port><%= @port %></Port>
3
+ <UrlBase>/sonarr</UrlBase>
4
+ <BindAddress>*</BindAddress>
5
+ <SslPort><%= @ssl_port %></SslPort>
6
+ <EnableSsl>False</EnableSsl>
7
+ <ApiKey><%= @api_key %></ApiKey>
8
+ <AuthenticationMethod>Forms</AuthenticationMethod>
9
+ <LogLevel>Info</LogLevel>
10
+ <LaunchBrowser>False</LaunchBrowser>
11
+ <Branch>develop</Branch>
12
+ <SslCertHash>
13
+ </SslCertHash>
14
+ <UpdateMechanism>BuiltIn</UpdateMechanism>
15
+ <UpdateAutomatically>True</UpdateAutomatically>
16
+ </Config>
@@ -0,0 +1,6 @@
1
+ Redirect "/sonarr" "/sonarr/app"
2
+ <Location /sonarr/>
3
+ ProxyPass http://localhost:<%= @port %>
4
+ ProxyPassReverse http://localhost:<%= @port %>
5
+ Require all granted
6
+ </Location>
@@ -0,0 +1,9 @@
1
+ #!/bin/sh
2
+
3
+ xrdb $HOME/.Xresources
4
+ xsetroot -solid grey
5
+ #x-terminal-emulator -geometry 80x24+10+10 -ls -title "$VNCDESKTOP BOSS Desktop" &
6
+ #x-window-manager &
7
+ # Fix to make GNOME work
8
+ export XKL_XMODMAP_DISABLE=1
9
+ /etc/X11/Xsession
@@ -0,0 +1,41 @@
1
+ name: Remote Desktop (VNC)
2
+ script_name: vnc.rb
3
+ version: 0.1
4
+ required_aethernal_agent_version: "~> 0.1.0"
5
+ description: Manage your server with a remote desktop instance running xfce.
6
+ installation_type: global_install
7
+ configuration_type: multi_user
8
+ plain_name: vnc
9
+ built_in_updater: false
10
+ icon:
11
+ name: vnc.png
12
+ sha256sum: b49177a4d0b5a132267f9963e213a164633e946a56339425952169e0bcc4e779
13
+ services:
14
+ - vnc
15
+ actions:
16
+ restart:
17
+ user:
18
+ required: true
19
+ linux_user: true
20
+ configure_app_user:
21
+ port:
22
+ auto_generate_port: true
23
+ min: 5900
24
+ max: 5999
25
+ user:
26
+ required: true
27
+ linux_user: true
28
+ password:
29
+ required: false
30
+ auto_generate: true
31
+ display_values:
32
+ - port
33
+ - password
34
+ estimated_size_mb: 600
35
+ package:
36
+ apt:
37
+ "18.04":
38
+ packages:
39
+ - xfce4
40
+ - tightvncserver
41
+ - lxterminal
@@ -0,0 +1,14 @@
1
+ [Unit]
2
+ Description=Remote desktop service (VNC)
3
+ After=network-online.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ PIDFile=%h/.vnc/%H:<%= @offset %>.pid
8
+ ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill :<%= @offset %> > /dev/null 2>&1 || :'
9
+ ExecStart=/usr/bin/vncserver :<%= @offset %> -geometry 1440x900
10
+ ExecStop=/usr/bin/vncserver -kill :<%= @offset %>
11
+ Restart=on-failure
12
+
13
+ [Install]
14
+ WantedBy=default.target
@@ -0,0 +1,41 @@
1
+ class AethernalAgent::Vnc < AethernalAgent::App
2
+ def initialize(options = {})
3
+ super(options)
4
+ end
5
+
6
+ def install_packages(options = {})
7
+ super(options)
8
+
9
+ apt_package(packages: "pulseaudio xscreensaver gvfs-common", action: :remove)
10
+ end
11
+
12
+ def uninstall_packages(options = {})
13
+ super(options)
14
+ end
15
+
16
+ def remove_app_user(options = {})
17
+ super do
18
+ directory(home_folder_path(".vnc"), action: :delete)
19
+ end
20
+ end
21
+
22
+ def configure_app_user(options = {})
23
+ self.install_packages(options)
24
+
25
+ super(options) do |opts|
26
+ directory( home_folder_path(".vnc"), owner: self.user)
27
+
28
+ # Make xstartup executable so vnc can use it
29
+ aethernal_agent_file("xstartup", home_folder_path(".vnc/xstartup"), chmod: 0711, owner: self.user)
30
+
31
+ run_command("echo #{opts[:password]} | vncpasswd -f > #{home_folder_path('.vnc/passwd')}")
32
+
33
+ # VNC won't start if the passwd is too exposed.
34
+ file_settings(home_folder_path('.vnc/passwd'), owner: self.user, chmod: 0600)
35
+
36
+ opts.reverse_merge!(offset: opts[:port] - 5900, home: home_folder_path())
37
+
38
+ set_ownership(home_folder_path('.config/'), self.user)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,123 @@
1
+ module AethernalAgent
2
+ module Systemd
3
+ class SystemdStatus < OpenStruct;end
4
+
5
+ SYSTEMD_ACTIONS = ["stop", "start", "enable", "disable", "restart"]
6
+
7
+ def run_user_systemctl(action, options = {})
8
+ results = {}
9
+ if options[:service_name]
10
+ run_command("loginctl enable-linger #{self.user}")
11
+ result = run_command("sudo -iu #{self.user} systemctl --user #{action} #{options[:service_name]}")
12
+ if result == false
13
+ add_errors("Could not '#{action}' service '#{options[:service_name]}'")
14
+ end
15
+ results[options[:service_name]] = result
16
+ else
17
+ self.manifest.services.each do |service|
18
+ result = run_command("sudo -iu #{self.user} systemctl --user #{action} #{service}")
19
+ if result == false
20
+ add_errors("Could not '#{action}' service '#{service}'")
21
+ end
22
+ results[service] = result
23
+ end
24
+ end
25
+
26
+ return results
27
+ end
28
+
29
+ def create_service_file(options = {})
30
+ AethernalAgent.logger.debug("Creating systemd file with options: #{options}")
31
+ # Ensure dbus communication is possible as root
32
+ run_command('echo \'export XDG_RUNTIME_DIR="/run/user/$UID"\' > /etc/profile.d/02-fix-xdg.sh')
33
+
34
+ # Ensure that processes keep running once a user logs out
35
+ run_command("loginctl enable-linger #{self.user}")
36
+
37
+ directory( home_folder_path(".config/systemd/"), owner: self.user)
38
+ directory( home_folder_path(".config/systemd/user/"), owner: self.user)
39
+
40
+ must_start = options[:start] || true
41
+ must_enable = options[:enable] || true
42
+
43
+ if options[:template]
44
+ write_template(
45
+ template_path(options[:template]), #source
46
+ service_file_path(options[:service_name]),
47
+ options[:vars],
48
+ {
49
+ owner: options[:user]
50
+ }
51
+ )
52
+ elsif options[:file]
53
+ aethernal_agent_file(options[:file], service_file_path(options[:service_name]), owner: options[:user])
54
+ end
55
+
56
+ reload_systemd_config
57
+ enable if must_enable
58
+ restart if must_start
59
+ end
60
+
61
+ def reload_systemd_config
62
+ run_command("systemctl --user daemon-reload")
63
+ end
64
+
65
+ def get_systemd_status(service_file)
66
+ begin
67
+ f = IO.popen("sudo -iu #{self.user} systemctl --user status #{service_file}")
68
+ status = parse_systemd_status_text(f.readlines.join("\n"))
69
+ rescue Errno::ENOENT => e
70
+ return false
71
+ ensure
72
+ f.close
73
+ end
74
+
75
+ return status
76
+ end
77
+
78
+ def parse_systemd_status_text(text)
79
+ s = SystemdStatus.new
80
+
81
+ if text.present?
82
+ loaded_status, service_file_and_enabled = text.match(/Loaded: (\w*) \((.*;)/).captures
83
+ s.service_file_name, enabled_status = service_file_and_enabled.split(";")
84
+ active_status,running_status = text.match(/Active: (\w*)\ \((.*)\)/).captures
85
+
86
+ if text.include?("since")
87
+ active_status,running_status,s.since = text.match(/Active: (\w*)\ \((.*)\) since (.*);/).captures
88
+ s.main_pid = text.match(/Main PID: (\d*)/).captures.first
89
+ end
90
+ end
91
+
92
+ s.loaded = loaded_status == "loaded"
93
+ s.enabled = enabled_status == " enabled" # there is a space in the output here on purpose
94
+ s.active = active_status == "active"
95
+ s.running = running_status == "running"
96
+
97
+ return s
98
+ end
99
+
100
+ def service_file_path(service_name)
101
+ home_folder_path(File.join(".config/systemd/user/", service_name))
102
+ end
103
+
104
+ SYSTEMD_ACTIONS.each do |action|
105
+ define_method(action) do |options = {}|
106
+ AethernalAgent.logger.info("#{action} on #{self.manifest.name} (#{self.manifest.services.join(' ')})")
107
+ opts, errors = ensure_action_options(__method__,options)
108
+ send("systemd_user_#{action}", opts)
109
+ return create_return_args(opts)
110
+ end
111
+ end
112
+
113
+ # Dynamically create systemd_user_stop / start etc. actions
114
+ def method_missing(method_name, *args)
115
+ systemd_call = method_name.match(/^systemd_user_(\w*)$/)
116
+ if systemd_call && systemd_call[1] && SYSTEMD_ACTIONS.include?(systemd_call[1])
117
+ run_user_systemctl(systemd_call[1], args.first)
118
+ else
119
+ super
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,57 @@
1
+ require 'erb'
2
+ require 'aethernal_agent/filesystem'
3
+ require 'aethernal_agent/errors'
4
+
5
+ module AethernalAgent
6
+ class Template
7
+ include AethernalAgent::Filesystem
8
+ include AethernalAgent::Errors
9
+
10
+ attr_accessor :file, :parsed, :result, :template_path, :options
11
+
12
+ def initialize(template_path, vars, options)
13
+ self.template_path = template_path
14
+ self.options = options
15
+
16
+ vars.each do |k,v|
17
+ AethernalAgent.logger.debug("Setting #{k} to #{v} #{v.class}")
18
+ if [String, Symbol].include?(v.class)
19
+ eval("@#{k}= '#{v}'")
20
+ elsif v.is_a?(NilClass)
21
+ eval("@#{k}= nil")
22
+ else
23
+ eval("@#{k}= #{v}")
24
+ end
25
+ end
26
+ end
27
+
28
+ def parse
29
+ erb = ERB.new(File.open(self.template_path).read)
30
+ self.result = erb.result(binding)
31
+
32
+ if self.result
33
+ self.parsed = true
34
+ return true
35
+ else
36
+ return false
37
+ end
38
+ end
39
+
40
+ def write_to(path)
41
+ return false unless self.parsed
42
+
43
+ begin
44
+ file = File.open(path, "w")
45
+ AethernalAgent.logger.debug("Writing template to #{path}")
46
+ file << self.result
47
+ file.close
48
+
49
+ file_settings(path, self.options)
50
+
51
+ rescue StandardError => e
52
+ add_errors(e, path: path)
53
+ return false
54
+ end
55
+ end
56
+ end
57
+ end