Module: AethernalAgent::Systemd

Included in:
App
Defined in:
lib/aethernal_agent/systemd.rb

Defined Under Namespace

Classes: SystemdStatus

Constant Summary collapse

SYSTEMD_ACTIONS =
["stop", "start", "enable", "disable", "restart"]

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args) ⇒ Object

Dynamically create systemd_user_stop / start etc. actions



120
121
122
123
124
125
126
127
# File 'lib/aethernal_agent/systemd.rb', line 120

def method_missing(method_name, *args)
  systemd_call = method_name.match(/^systemd_user_(\w*)$/)
  if systemd_call && systemd_call[1] && SYSTEMD_ACTIONS.include?(systemd_call[1])
    run_user_systemctl(systemd_call[1], args.first)
  else
    super
  end
end

Instance Method Details

#create_service_file(options = {}) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/aethernal_agent/systemd.rb', line 33

def create_service_file(options = {})
  AethernalAgent.logger.debug("Creating systemd file with options: #{options}")
  # Ensure dbus communication is possible as root
  run_command('echo \'export XDG_RUNTIME_DIR="/run/user/$UID"\' > /etc/profile.d/02-fix-xdg.sh')

  # Ensure that processes keep running once a user logs out
  run_command("loginctl enable-linger #{self.user}")

  directory( home_folder_path(".config/systemd/"), owner: self.user)
  directory( home_folder_path(".config/systemd/user/"), owner: self.user)

  must_start = options[:start] || true
  must_enable = options[:enable] || true

  if options[:template]
    write_template(
      template_path(options[:template]), #source
      service_file_path(options[:service_name]),
      options[:vars].reverse_merge(container_name: self.docker_container_name),
        {
          owner: options[:user]
        }
    )
  elsif options[:file]
    aethernal_agent_file(options[:file], service_file_path(options[:service_name]), owner: options[:user])
  end

  reload_systemd_config
  enable if must_enable
  restart if must_start
end

#get_systemd_status(service_file) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/aethernal_agent/systemd.rb', line 69

def get_systemd_status(service_file)
  begin
    f = IO.popen("sudo -iu #{self.user} systemctl --user status #{service_file}")
    status = parse_systemd_status_text(f.readlines.join("\n"))
  rescue Errno::ENOENT => e
    return false
  ensure
    f.close
  end

  return status
end

#parse_systemd_status_text(text) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/aethernal_agent/systemd.rb', line 82

def parse_systemd_status_text(text)
  s = SystemdStatus.new

  if text.present?
    loaded_status, service_file_and_enabled = text.match(/Loaded: (\w*) \((.*;)/).captures
    s.service_file_name, enabled_status = service_file_and_enabled.split(";")
    active_status,running_status = text.match(/Active: (\w*)\ \((.*)\)/).captures

    if text.include?("since")
      active_status,running_status,s.since = text.match(/Active: (\w*)\ \((.*)\) since (.*);/).captures
      s.main_pid = text.match(/Main PID: (\d*)/).captures.first
    end
  end

  s.loaded = loaded_status == "loaded"
  s.enabled = enabled_status == " enabled" # there is a space in the output here on purpose
  s.active = active_status == "active"
  s.running = running_status == "running"

  return s
end

#reload_systemd_configObject



65
66
67
# File 'lib/aethernal_agent/systemd.rb', line 65

def reload_systemd_config
  run_command("systemctl --user daemon-reload")
end

#run_user_systemctl(action, options = {}) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/aethernal_agent/systemd.rb', line 7

def run_user_systemctl(action, options = {})
  results = {}
  if options[:service_name]
    run_command("loginctl enable-linger #{self.user}")
    result = run_command("sudo -iu #{self.user} systemctl --user #{action} #{options[:service_name]}")
    if result == false
      add_errors("Could not '#{action}' service '#{options[:service_name]}'")
    end
    results[options[:service_name]] = result
  elsif self.manifest.services.present?
    self.manifest.services.each do |service|
      if File.exist?(service_file_path("#{service}.service"))
        result = run_command("sudo -iu #{self.user} systemctl --user #{action} #{service}")
        if result == false
          add_errors("Could not '#{action}' service '#{service}'")
        end
        results[service] = result
      else
        AethernalAgent.logger.debug("Service file service_file_path(#{service}.service did not exist, not trying to do action.")
      end
    end
  end

  return results
end

#service_file_path(service_name) ⇒ Object



104
105
106
# File 'lib/aethernal_agent/systemd.rb', line 104

def service_file_path(service_name)
  home_folder_path(File.join(".config/systemd/user/", service_name))
end