Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NAS-131141 / 25.04 / Shutdown/reboot audit #14546

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
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
25 changes: 0 additions & 25 deletions debian/debian/ix-freebsd-to-scale-update.service

This file was deleted.

1 change: 0 additions & 1 deletion debian/debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ override_dh_installsystemd:
dh_installsystemd --no-start -r --no-restart-after-upgrade --name=ix-boot-core
dh_installsystemd --no-start -r --no-restart-after-upgrade --name=ix-cgroups
dh_installsystemd --no-start -r --no-restart-after-upgrade --name=ix-etc
dh_installsystemd --no-start -r --no-restart-after-upgrade --name=ix-freebsd-to-scale-update
dh_installsystemd --no-start -r --no-restart-after-upgrade --name=ix-netif
dh_installsystemd --no-start -r --no-restart-after-upgrade --name=ix-postinit
dh_installsystemd --no-start -r --no-restart-after-upgrade --name=ix-preinit
Expand Down
3 changes: 2 additions & 1 deletion src/middlewared/middlewared/api/v25_04_0/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from .group import * # noqa
from .keychain import * # noqa
from .privilege import * # noqa
from .smartctl import * # noqa
from .system_reboot import * # noqa
from .system_lifecycle import * # noqa
from .user import * # noqa
from .vendor import * # noqa
from .smartctl import * # noqa
2 changes: 0 additions & 2 deletions src/middlewared/middlewared/api/v25_04_0/smartctl.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Any

from middlewared.api.base import BaseModel

__all__ = ["AtaSelfTest", "NvmeSelfTest", "ScsiSelfTest"]
Expand Down
32 changes: 32 additions & 0 deletions src/middlewared/middlewared/api/v25_04_0/system_lifecycle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from pydantic import Field

from middlewared.api.base import BaseModel, NonEmptyString

__all__ = ["SystemRebootArgs", "SystemRebootResult",
"SystemShutdownArgs", "SystemShutdownResult"]


class SystemRebootOptions(BaseModel):
delay: int | None = None


class SystemRebootArgs(BaseModel):
reason: NonEmptyString
options: SystemRebootOptions = Field(default=SystemRebootOptions())


class SystemRebootResult(BaseModel):
result: None


class SystemShutdownOptions(BaseModel):
delay: int | None = None


class SystemShutdownArgs(BaseModel):
reason: NonEmptyString
options: SystemShutdownOptions = Field(default=SystemShutdownOptions())


class SystemShutdownResult(BaseModel):
result: None
24 changes: 17 additions & 7 deletions src/middlewared/middlewared/plugins/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import tempfile

from middlewared.schema import accepts, Bool, Dict, returns
from middlewared.service import CallError, Service, job, private
from middlewared.service import CallError, Service, job, pass_app, private
from middlewared.plugins.pwenc import PWENC_FILE_SECRET
from middlewared.utils.db import FREENAS_DATABASE

Expand All @@ -26,6 +26,8 @@
TRUENAS_ADMIN_KEYS_UPLOADED = '/data/truenas_admin_authorized_keys_uploaded'
ROOT_KEYS_UPLOADED = '/data/root_authorized_keys_uploaded'
DATABASE_NAME = os.path.basename(FREENAS_DATABASE)
CONFIGURATION_UPLOAD_REBOOT_REASON = 'Configuration upload'
CONFIGURATION_RESET_REBOOT_REASON = 'Configuration reset'


class ConfigService(Service):
Expand Down Expand Up @@ -84,7 +86,8 @@ async def save(self, job, options):
@accepts()
@returns()
@job(pipes=["input"])
def upload(self, job):
@pass_app(rest=True)
def upload(self, app, job):
"""
Accepts a configuration file via job pipe.
"""
Expand All @@ -105,7 +108,10 @@ def upload(self, job):
is_tar = tarfile.is_tarfile(stf.name)
self.upload_impl(stf.name, is_tar_file=is_tar)

self.middleware.run_coroutine(self.middleware.call('system.reboot', {'delay': 10}), wait=False)
self.middleware.run_coroutine(
self.middleware.call('system.reboot', CONFIGURATION_UPLOAD_REBOOT_REASON, {'delay': 10}, app=app),
wait=False,
)

@private
def upload_impl(self, file_or_tar, is_tar_file=False):
Expand Down Expand Up @@ -180,7 +186,7 @@ def upload_impl(self, file_or_tar, is_tar_file=False):
'failover.call_remote', 'core.call_hook', ['config.on_upload', [UPLOADED_DB_PATH]]
)
self.middleware.run_coroutine(
self.middleware.call('failover.call_remote', 'system.reboot'),
self.middleware.call('failover.call_remote', 'system.reboot', CONFIGURATION_UPLOAD_REBOOT_REASON),
wait=False,
)
except Exception as e:
Expand All @@ -193,7 +199,8 @@ def upload_impl(self, file_or_tar, is_tar_file=False):
@accepts(Dict('options', Bool('reboot', default=True)))
@returns()
@job(lock='config_reset', logs=True)
def reset(self, job, options):
@pass_app(rest=True)
def reset(self, app, job, options):
"""
Reset database to configuration defaults.

Expand Down Expand Up @@ -224,7 +231,9 @@ def reset(self, job, options):

if options['reboot']:
self.middleware.run_coroutine(
self.middleware.call('failover.call_remote', 'system.reboot'),
self.middleware.call(
'failover.call_remote', 'system.reboot', CONFIGURATION_UPLOAD_REBOOT_REASON,
),
wait=False,
)
except Exception as e:
Expand All @@ -240,7 +249,8 @@ def reset(self, job, options):
if options['reboot']:
job.set_progress(95, 'Will reboot in 10 seconds')
self.middleware.run_coroutine(
self.middleware.call('system.reboot', {'delay': 10}), wait=False,
self.middleware.call('system.reboot', CONFIGURATION_RESET_REBOOT_REASON, {'delay': 10}, app=app),
wait=False,
)

@private
Expand Down
7 changes: 3 additions & 4 deletions src/middlewared/middlewared/plugins/failover.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from middlewared.plugins.failover_.configure import HA_LICENSE_CACHE_KEY
from middlewared.plugins.failover_.remote import NETWORK_ERRORS
from middlewared.plugins.system.reboot import RebootReason
from middlewared.plugins.update import SYSTEM_UPGRADE_REBOOT_REASON
from middlewared.plugins.update_.install import STARTING_INSTALLER
from middlewared.plugins.update_.utils import DOWNLOAD_UPDATE_FILE
from middlewared.plugins.update_.utils_linux import mount_update
Expand Down Expand Up @@ -388,7 +389,7 @@ def sync_to_peer(self, options):
)

if options['reboot']:
self.middleware.call_sync('failover.call_remote', 'system.reboot', [{'delay': 2}])
self.middleware.call_sync('failover.call_remote', 'system.reboot', 'Failover sync to peer', [{'delay': 2}])
yocalebo marked this conversation as resolved.
Show resolved Hide resolved

@accepts(roles=['FAILOVER_WRITE'])
@returns()
Expand Down Expand Up @@ -858,9 +859,7 @@ def callback(j, controller):
rjob.result()

self.middleware.call_sync(
'failover.call_remote', 'system.reboot',
[{'delay': 5}],
{'job': True}
'failover.call_remote', 'system.reboot', SYSTEM_UPGRADE_REBOOT_REASON, [{'delay': 5}], {'job': True},
)
except Exception:
raise
Expand Down
2 changes: 0 additions & 2 deletions src/middlewared/middlewared/plugins/service_/services/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
RoutingService,
SslService,
SyslogdService,
SystemService,
TimeservicesService,
UserService,
)
Expand Down Expand Up @@ -78,7 +77,6 @@
RoutingService,
SslService,
SyslogdService,
SystemService,
TimeservicesService,
TruecommandService,
UserService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,18 +172,6 @@ class SyslogdService(SimpleService):
systemd_unit = "syslog-ng"


class SystemService(PseudoServiceBase):
name = "system"

restartable = True

async def stop(self):
self.middleware.create_task(self.middleware.call("system.shutdown", {"delay": 3}))

async def restart(self):
self.middleware.create_task(self.middleware.call("system.reboot", {"delay": 3}))


class TimeservicesService(PseudoServiceBase):
name = "timeservices"

Expand Down
4 changes: 3 additions & 1 deletion src/middlewared/middlewared/plugins/sysdataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,9 @@ async def do_update(self, job, data):
if await self.middleware.call('failover.licensed'):
if await self.middleware.call('failover.status') == 'MASTER':
try:
await self.middleware.call('failover.call_remote', 'system.reboot')
await self.middleware.call(
'failover.call_remote', 'system.reboot', 'Failover system dataset change',
)
except Exception as e:
self.logger.debug('Failed to reboot standby storage controller after system dataset change: %s', e)

Expand Down
40 changes: 20 additions & 20 deletions src/middlewared/middlewared/plugins/system/lifecycle.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import asyncio

from middlewared.schema import accepts, Bool, Dict, Int, returns, Str
from middlewared.api import api_method
from middlewared.api.current import SystemRebootArgs, SystemRebootResult, SystemShutdownArgs, SystemShutdownResult
from middlewared.schema import accepts, Bool, returns, Str
from middlewared.service import job, private, Service, no_auth_required, pass_app
from middlewared.utils import Popen, run
from middlewared.utils import run

from .utils import lifecycle_conf, RE_KDUMP_CONFIGURED

Expand All @@ -19,7 +21,7 @@ async def first_boot(self):
@pass_app()
async def boot_id(self, app):
"""
Returns an unique boot identifier.
Returns a unique boot identifier.

It is supposed to be unique every system boot.
"""
Expand Down Expand Up @@ -53,41 +55,39 @@ async def state(self):
return 'READY'
return 'BOOTING'

@accepts(Dict('system-reboot', Int('delay', required=False), required=False))
@returns()
@api_method(SystemRebootArgs, SystemRebootResult)
@job()
async def reboot(self, job, options):
@pass_app(rest=True)
async def reboot(self, app, job, reason, options):
"""
Reboots the operating system.

Emits an "added" event of name "system" and id "reboot".
"""
if options is None:
options = {}
await self.middleware.log_audit_message(app, 'REBOOT', {'reason': reason}, True)

self.middleware.send_event('system.reboot', 'ADDED')
self.middleware.send_event('system.reboot', 'ADDED', fields={'reason': reason})

delay = options.get('delay')
if delay:
await asyncio.sleep(delay)
if options['delay'] is not None:
await asyncio.sleep(options['delay'])

await run(['/sbin/shutdown', '-r', 'now'])

@accepts(Dict('system-shutdown', Int('delay', required=False), required=False))
@returns()
@api_method(SystemShutdownArgs, SystemShutdownResult)
@job()
async def shutdown(self, job, options):
@pass_app(rest=True)
async def shutdown(self, app, job, reason, options):
"""
Shuts down the operating system.

An "added" event of name "system" and id "shutdown" is emitted when shutdown is initiated.
"""
if options is None:
options = {}
await self.middleware.log_audit_message(app, 'SHUTDOWN', {'reason': reason}, True)

delay = options.get('delay')
if delay:
await asyncio.sleep(delay)
self.middleware.send_event('system.shutdown', 'ADDED', fields={'reason': reason})

if options['delay'] is not None:
await asyncio.sleep(options['delay'])

await run(['/sbin/poweroff'])

Expand Down
9 changes: 6 additions & 3 deletions src/middlewared/middlewared/plugins/update.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from middlewared.schema import accepts, Bool, Dict, Str
from middlewared.service import job, private, CallError, Service
from middlewared.service import job, private, CallError, Service, pass_app
import middlewared.sqlalchemy as sa
from middlewared.plugins.update_.utils import UPLOAD_LOCATION
from middlewared.utils import PRODUCT
Expand All @@ -13,6 +13,8 @@
import textwrap
import pathlib

SYSTEM_UPGRADE_REBOOT_REASON = 'System upgrade'


def parse_train_name(name):
split = (name + '-').split('-')
Expand Down Expand Up @@ -256,7 +258,8 @@ async def get_pending(self, path):
Bool('reboot', default=False),
))
@job(lock='update')
async def update(self, job, attrs):
@pass_app(rest=True)
async def update(self, app, job, attrs):
"""
Downloads (if not already in cache) and apply an update.

Expand Down Expand Up @@ -288,7 +291,7 @@ async def update(self, job, attrs):
await self.middleware.call_hook('update.post_update')

if attrs['reboot']:
await self.middleware.call('system.reboot', {'delay': 10})
await self.middleware.call('system.reboot', SYSTEM_UPGRADE_REBOOT_REASON, {'delay': 10}, app=app)

return True

Expand Down

This file was deleted.

Loading
Loading