Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/core/src/core_logic/ServiceManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,18 @@ def is_service_enabled(self):
# endregion

# region - Service Unit Management
def create_service_unit_file(self, exec_start, desc, after="network.target", service_type="forking", wanted_by="multi-user.target"):
def create_service_unit_file(self, exec_start, desc, after="network.target", service_type="forking", timeout_start_sec="10min", wanted_by="multi-user.target"):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that the potential collision surface between Auto Assessment and imperative patching calls has increased, could you please validate that this scenario is handled correctly? Specifically, it would be useful to initiate an InstallPatches call while an assessment is in progress and verify the behavior.

Although this is a relatively small change, I believe we should let it bake sufficiently in the canary region to observe and address any unforeseen issues before broader rollout.

As I understand it, with this approach, if an assessment completes quickly, say within 60 seconds, the process exits immediately and gracefully. The 10-minute timeout only comes into play for assessments that are delayed or take longer than expected to complete.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

""" Note: Service type defaults to forking because of sh to py process fork """
service_unit_content_template = "\n[Unit]" + \
"\nDescription={0}" + \
"\nAfter={1}\n" + \
"\n[Service]" + \
"\nType={2}" + \
"\nExecStart={3}\n" + \
"\nExecStart={3}" + \
"\nTimeoutStartSec={4}\n" + \
"\n[Install]" + \
"\nWantedBy={4}"
service_unit_content = service_unit_content_template.format(desc, after, service_type, exec_start, wanted_by)
"\nWantedBy={5}"
service_unit_content = service_unit_content_template.format(desc, after, service_type, exec_start, timeout_start_sec, wanted_by)
service_unit_path = self.__systemd_service_unit_path.format(self.service_name)
self.env_layer.file_system.write_with_retry(service_unit_path, service_unit_content)
self.env_layer.run_command_output("sudo chmod 644 " + service_unit_path) # 644 = Owner: RW; Group: R; Others: R
Expand Down
10 changes: 9 additions & 1 deletion src/core/tests/Test_ServiceManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ def setUp(self):
self.service_manager = ServiceManager(self.runtime.env_layer, self.runtime.execution_config, self.runtime.composite_logger, self.runtime.telemetry_writer,ServiceInfo("AutoAssessment", "Auto assessment service", "path"))
self.service_manager.service_name = "test_service"
self.mock_systemd_service_unit_path = "/etc/systemd/system/{0}.service"
self.written_service_unit_path = None
self.written_service_unit_content = None

def tearDown(self):
self.runtime.stop()
Expand All @@ -38,6 +40,8 @@ def mock_run_command_to_set_service_file_permission(self, cmd, no_output=False,
return 0, "permissions set"

def mock_write_with_retry_valid(self, file_path_or_handle, data, mode='a+'):
self.written_service_unit_path = file_path_or_handle
self.written_service_unit_content = data
return

def mock_invoke_systemctl(self, command, description):
Expand All @@ -58,11 +62,15 @@ def mock_invoke_systemctl(self, command, description):
elif "is-active" in command:
return 0, "Checking if service is active"

def test_create_service_unit_file(self):
def test_create_service_unit_file_sets_ten_minute_start_timeout(self):
self.service_manager.env_layer.run_command_output = self.mock_run_command_to_set_service_file_permission
self.service_manager.env_layer.file_system.write_with_retry = self.mock_write_with_retry_valid
self.service_manager.create_service_unit_file(exec_start="/bin/bash " + self.service_manager.service_exec_path, desc="Microsoft Azure Linux Patch Extension - Auto Assessment")

self.assertEqual("/etc/systemd/system/test_service.service", self.written_service_unit_path)
self.assertIn("\nType=forking\n", self.written_service_unit_content)
self.assertIn("\nTimeoutStartSec=10min\n", self.written_service_unit_content)

def test_start_service(self):
# Set method calls
self.service_manager.invoke_systemctl_called = False
Expand Down
Loading