Skip to content
Permalink
Browse files

Move `SystemdServiceClass` module to real `SystemdService` class

  • Loading branch information...
dgdavid committed Aug 14, 2018
1 parent 3586c81 commit f1954531296f564a7d0ff3d26fa05769d247919a
@@ -34,7 +34,7 @@ class ServiceStatus
include Yast::I18n
include Yast::Logger

# @param service [Yast::SystemdServiceClass::Service] systemd service. Usually the easiest way
# @param service [Yast::SystemdService] systemd service. Usually the easiest way
# is just calling `Yast::SystemdService.find("name_of_the_service")`
# Note that this widget will #start and #stop the service by itself but
# the actions referenced by the flags (reloading and enabling/disabling)
@@ -42,6 +42,7 @@
# The network.service alias link obsoletes the old master switch in
# /etc/sysconfig/network/config:NETWORKMANAGER (until openSUSE-12.2).
require "yast"
require "yast2/systemd_service"

module Yast
class NetworkServiceClass < Module
@@ -73,7 +74,6 @@ class NetworkServiceClass < Module
include Yast::Logger

def main
Yast.import "SystemdService"
Yast.import "NetworkConfig"
Yast.import "Popup"
Yast.import "Mode"
@@ -31,10 +31,9 @@
# Functions for systemd service handling used by other modules.

require "yast"
require "yast2/systemd_service"

module Yast
import "SystemdService"

class ServiceClass < Module
include Yast::Logger

@@ -9,7 +9,7 @@ module Yast
include SystemdServiceStubs

def stub_service_with(method, result)
allow_any_instance_of(SystemdServiceClass::Service).to receive(method)
allow_any_instance_of(SystemdService).to receive(method)
.and_return(result)
end

@@ -2,10 +2,9 @@

require "yast2/service_widget"
require "yast2/service_configuration"
require "yast2/systemd_service"
require "ui/service_status"

Yast.import "SystemdService"

def service
@service ||= Yast::SystemdService.find!("cups.service")
end
@@ -0,0 +1,214 @@
require "yast2/systemd_unit"

module Yast
# Represent a missed service
class SystemdServiceNotFound < StandardError
def initialize(service_name)
super "Service unit '#{service_name}' not found"
end
end

# Systemd.service unit control API
#
# @example How to use it in other yast libraries
# require 'yast'
# Yast.import 'SystemdService'
#
# ## Get a service unit by its name
# ## If the service unit can't be found, you'll get nil
#
# service = Yast::SystemdService.find('sshd') # service unit object
#
# # or using the full unit id 'sshd.service'
#
# service = Yast::SystemdService.find('sshd.service')
#
# ## If you can't handle any nil at the place of calling,
# ## use the finder with exclamation mark;
# ## SystemdServiceNotFound exception will be raised
#
# service = Yast::SystemdService.find!('IcanHasMoar') # SystemdServiceNotFound: Service unit 'IcanHasMoar' not found
#
# ## Get basic unit properties
#
# service.unit_name # 'sshd'
# service.unit_type # 'service'
# service.id # 'sshd.service'
# service.description # 'OpenSSH Daemon'
# service.path # '/usr/lib/systemd/system/sshd.service'
# service.loaded? # true if it's loaded, false otherwise
# service.running? # true if it's active and running
# service.enabled? # true if enabled, false otherwise
# service.disabled? # true if disabled, false otherwise
# service.status # the same text output you get with `systemctl status sshd.service`
# service.show # equivalent of calling `systemctl show sshd.service`
#
# ## Service unit file commands
#
# # Unit file commands do modifications on the service unit. Calling them triggers
# # service properties reloading. If a command fails, the error message is available
# # through the method #error as a string.
#
# service.start # true if unit has been activated successfully
# service.stop # true if unit has been deactivated successfully
# service.enable # true if unit has been enabled successfully
# service.disable # true if unit has been disabled successfully
# service.error # error string available if some of the actions above fails
#
# ## Extended service properties
#
# # In case you need more details about the service unit than the default ones,
# # you can extend the parameters for .find method. Those properties are
# # then available on the service unit object under the #properties instance method.
# # An extended property is always a string, you must convert it manually,
# # no automatical casting is done by yast.
# # To get an overview of available service properties, try e.g., `systemctl show sshd.service`
#
# service = Yast::SystemdService.find('sshd', :type=>'Type')
# service.properties.type # 'simple'
class SystemdService < SystemdUnit
Yast.import "Stage"
include Yast::Logger

UNIT_SUFFIX = ".service".freeze

class << self
# @param service_name [String] "foo" or "foo.service"
# @param propmap [SystemdUnit::PropMap]
# @return [Service,nil] `nil` if not found
def find(service_name, propmap = {})
service = build(service_name, propmap)
return nil if service.properties.not_found?
service
end

# @param service_name [String] "foo" or "foo.service"
# @param propmap [SystemdUnit::PropMap]
# @return [Service]
# @raise [SystemdServiceNotFound]
def find!(service_name, propmap = {})
find(service_name, propmap) || raise(SystemdServiceNotFound, service_name)
end

# @param service_names [Array<String>] "foo" or "foo.service"
# @param propmap [SystemdUnit::PropMap]
# @return [Array<Service,nil>] `nil` if a service is not found,
# [] if this helper cannot be used:
# either we're in the inst-sys without systemctl,
# or it has returned fewer services than requested
# (and we cannot match them up)
def find_many_at_once(service_names, propmap = {})
return [] if Stage.initial

snames = service_names.map { |n| n + UNIT_SUFFIX unless n.end_with?(UNIT_SUFFIX) }
snames_s = snames.join(" ")
pnames_s = SystemdUnit::DEFAULT_PROPMAP.merge(propmap).values.join(",")
out = Systemctl.execute("show --property=#{pnames_s} #{snames_s}")
log.error "returned #{out.exit}, #{out.stderr}" unless out.exit.zero? && out.stderr.empty?
property_texts = out.stdout.split("\n\n")
return [] unless snames.size == property_texts.size

snames.zip(property_texts).each_with_object([]) do |(name, property_text), memo|
service = new(name, propmap, property_text)
memo << service unless service.not_found?
end
end

# @param service_names [Array<String>] "foo" or "foo.service"
# @param propmap [SystemdUnit::PropMap]
# @return [Array<Service,nil>] `nil` if not found
def find_many(service_names, propmap = {})
services = find_many_at_once(service_names, propmap)
return services unless services.empty?

log.info "Retrying one by one"
service_names.map { |n| find(n, propmap) }
end

# @param propmap [SystemdUnit::PropMap]
# @return [Array<Service>]
def all(propmap = {})
Systemctl.service_units.map { |service_unit| new(service_unit, propmap) }
end

# Instantiate a SystemdService object based on the given name
#
# Use with caution as the service might exist or not. If you need to react when
# the service does not exist, use SystemdServiceClass.find.
#
# @param service_name [String] "foo" or "foo.service"
# @param propmap [SystemdUnit::PropMap]
# @return [Service] System service with the given name
def build(service_name, propmap = {})
service_name += UNIT_SUFFIX unless service_name.end_with?(UNIT_SUFFIX)
new(service_name, propmap)
end
end

private_class_method :find_many_at_once

# Available only on installation system
START_SERVICE_INSTSYS_COMMAND = "/bin/service_start".freeze

# @return [String]
def pid
properties.pid
end

def running?
properties.running?
end

def static?
properties.static?
end

def start
command = "#{START_SERVICE_INSTSYS_COMMAND} #{unit_name}"
installation_system? ? run_instsys_command(command) : super
end

def stop
command = "#{START_SERVICE_INSTSYS_COMMAND} --stop #{unit_name}"
installation_system? ? run_instsys_command(command) : super
end

def restart
# Delegate to SystemdUnit#restart if not within installation
return super unless installation_system?

stop
sleep(1)
start
end

# Returns socket associated with service or nil if there is no such socket
#
# @return [Yast::SystemdSocketClass::Socket,nil]
# @see SystemdSocket.for_service
def socket
@socket ||= Yast::SystemdSocket.for_service(name)
end

# Determines whether the service has an associated socket
#
# @return [Boolean] true if an associated socket exists; false otherwise.
def socket?
!socket.nil?
end

def installation_system?
File.exist?(START_SERVICE_INSTSYS_COMMAND)
end

def run_instsys_command(command)
log.info("Running command '#{command}'")
error.clear
result = OpenStruct.new(
SCR.Execute(Path.new(".target.bash_output"), command)
)
error << result.stderr
result.exit.zero?
end
end
end
@@ -3,8 +3,6 @@
require_relative "test_helper"

module Yast
import "SystemdService"

describe SystemdService do
include SystemdServiceStubs

@@ -99,8 +97,8 @@ module Yast
let(:not_found_double) { double("Service", name: "cups", not_found?: true) }

before do
allow(Yast::SystemdServiceClass::Service).to receive(:new).and_call_original
allow(Yast::SystemdServiceClass::Service).to receive(:new)
allow(Yast::SystemdService).to receive(:new).and_call_original
allow(Yast::SystemdService).to receive(:new)
.with("cups.service", anything, anything)
.and_return(not_found_double)
end
@@ -167,7 +165,7 @@ module Yast

context "Restart a service on the installation system" do
it "restarts a service with a specialized inst-sys helper if available" do
allow_any_instance_of(SystemdServiceClass::Service).to receive(:sleep).and_return(1)
allow_any_instance_of(SystemdService).to receive(:sleep).and_return(1)
allow(File).to receive(:exist?).with("/bin/service_start").and_return(true)
service = SystemdService.find("sshd")
allow(SCR).to receive(:Execute).and_return("stderr" => "", "stdout" => "", "exit" => 0)
@@ -1,9 +1,9 @@
require_relative "../../../test/test_helper.rb"

require "yast2/systemd_unit"
require "yast2/systemd_service"

Yast.import "SystemdSocket"
Yast.import "SystemdService"
Yast.import "SystemdTarget"

# Find a Term in given content
@@ -27,7 +27,7 @@
subject(:system_service) { described_class.new(service) }

let(:service) do
instance_double(Yast::SystemdServiceClass::Service,
instance_double(Yast::SystemdService,
name: "cups",
enabled?: service_enabled,
active?: service_active,
@@ -62,7 +62,7 @@
end

context "when the service is found" do
let(:systemd_service) { instance_double(Yast::SystemdServiceClass::Service) }
let(:systemd_service) { instance_double(Yast::SystemdService) }

it "returns the service" do
system_service = described_class.find("cups")
@@ -87,7 +87,7 @@
end

context "when the service is found" do
let(:systemd_service) { instance_double(Yast::SystemdServiceClass::Service) }
let(:systemd_service) { instance_double(Yast::SystemdService) }

it "returns the service" do
system_service = described_class.find!("cups")
@@ -107,7 +107,7 @@
end

describe ".build" do
let(:systemd_service) { instance_double(Yast::SystemdServiceClass::Service) }
let(:systemd_service) { instance_double(Yast::SystemdService) }

it "returns a systemd service with the given name" do
expect(Yast::SystemdService).to receive(:build).with("other")
@@ -118,8 +118,8 @@
end

describe ".find_many" do
let(:apparmor) { instance_double(Yast::SystemdServiceClass::Service) }
let(:cups) { instance_double(Yast::SystemdServiceClass::Service) }
let(:apparmor) { instance_double(Yast::SystemdService) }
let(:cups) { instance_double(Yast::SystemdService) }

before do
allow(Yast::SystemdService).to receive(:find_many).with(["apparmor", "cups"])

0 comments on commit f195453

Please sign in to comment.
You can’t perform that action at this time.