Migrate install handling to operator native
Change-Id: I0d06db0c8ac15b3a1fd3e9c4b4f0d2243fb1875e
This commit is contained in:
parent
1ee3d04fda
commit
3959512fb3
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,219 @@
|
|||
# Copyright 2021 Canonical Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
"""Abstractions for stopping, starting and managing system services via systemd.
|
||||
|
||||
This library assumes that your charm is running on a platform that uses systemd. E.g.,
|
||||
Centos 7 or later, Ubuntu Xenial (16.04) or later.
|
||||
|
||||
For the most part, we transparently provide an interface to a commonly used selection of
|
||||
systemd commands, with a few shortcuts baked in. For example, service_pause and
|
||||
service_resume with run the mask/unmask and enable/disable invocations.
|
||||
|
||||
Example usage:
|
||||
```python
|
||||
from charms.operator_libs_linux.v0.systemd import service_running, service_reload
|
||||
|
||||
# Start a service
|
||||
if not service_running("mysql"):
|
||||
success = service_start("mysql")
|
||||
|
||||
# Attempt to reload a service, restarting if necessary
|
||||
success = service_reload("nginx", restart_on_failure=True)
|
||||
```
|
||||
|
||||
"""
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
__all__ = [ # Don't export `_systemctl`. (It's not the intended way of using this lib.)
|
||||
"service_pause",
|
||||
"service_reload",
|
||||
"service_restart",
|
||||
"service_resume",
|
||||
"service_running",
|
||||
"service_start",
|
||||
"service_stop",
|
||||
"daemon_reload",
|
||||
]
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# The unique Charmhub library identifier, never change it
|
||||
LIBID = "045b0d179f6b4514a8bb9b48aee9ebaf"
|
||||
|
||||
# Increment this major API version when introducing breaking changes
|
||||
LIBAPI = 1
|
||||
|
||||
# Increment this PATCH version before using `charmcraft publish-lib` or reset
|
||||
# to 0 if you are raising the major API version
|
||||
LIBPATCH = 0
|
||||
|
||||
|
||||
class SystemdError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _popen_kwargs():
|
||||
return dict(
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
bufsize=1,
|
||||
universal_newlines=True,
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
def _systemctl(
|
||||
sub_cmd: str, service_name: str = None, now: bool = None, quiet: bool = None
|
||||
) -> bool:
|
||||
"""Control a system service.
|
||||
|
||||
Args:
|
||||
sub_cmd: the systemctl subcommand to issue
|
||||
service_name: the name of the service to perform the action on
|
||||
now: passes the --now flag to the shell invocation.
|
||||
quiet: passes the --quiet flag to the shell invocation.
|
||||
"""
|
||||
cmd = ["systemctl", sub_cmd]
|
||||
|
||||
if service_name is not None:
|
||||
cmd.append(service_name)
|
||||
if now is not None:
|
||||
cmd.append("--now")
|
||||
if quiet is not None:
|
||||
cmd.append("--quiet")
|
||||
if sub_cmd != "is-active":
|
||||
logger.debug("Attempting to {} '{}' with command {}.".format(cmd, service_name, cmd))
|
||||
else:
|
||||
logger.debug("Checking if '{}' is active".format(service_name))
|
||||
|
||||
proc = subprocess.Popen(cmd, **_popen_kwargs())
|
||||
last_line = ""
|
||||
for line in iter(proc.stdout.readline, ""):
|
||||
last_line = line
|
||||
logger.debug(line)
|
||||
|
||||
proc.wait()
|
||||
|
||||
if sub_cmd == "is-active":
|
||||
# If we are just checking whether a service is running, return True/False, rather
|
||||
# than raising an error.
|
||||
if proc.returncode < 1:
|
||||
return True
|
||||
if proc.returncode == 3: # Code returned when service is not active.
|
||||
return False
|
||||
|
||||
if proc.returncode < 1:
|
||||
return True
|
||||
|
||||
raise SystemdError(
|
||||
"Could not {}{}: systemd output: {}".format(
|
||||
sub_cmd, " {}".format(service_name) if service_name else "", last_line
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def service_running(service_name: str) -> bool:
|
||||
"""Determine whether a system service is running.
|
||||
|
||||
Args:
|
||||
service_name: the name of the service
|
||||
"""
|
||||
return _systemctl("is-active", service_name, quiet=True)
|
||||
|
||||
|
||||
def service_start(service_name: str) -> bool:
|
||||
"""Start a system service.
|
||||
|
||||
Args:
|
||||
service_name: the name of the service to stop
|
||||
"""
|
||||
return _systemctl("start", service_name)
|
||||
|
||||
|
||||
def service_stop(service_name: str) -> bool:
|
||||
"""Stop a system service.
|
||||
|
||||
Args:
|
||||
service_name: the name of the service to stop
|
||||
"""
|
||||
return _systemctl("stop", service_name)
|
||||
|
||||
|
||||
def service_restart(service_name: str) -> bool:
|
||||
"""Restart a system service.
|
||||
|
||||
Args:
|
||||
service_name: the name of the service to restart
|
||||
"""
|
||||
return _systemctl("restart", service_name)
|
||||
|
||||
|
||||
def service_reload(service_name: str, restart_on_failure: bool = False) -> bool:
|
||||
"""Reload a system service, optionally falling back to restart if reload fails.
|
||||
|
||||
Args:
|
||||
service_name: the name of the service to reload
|
||||
restart_on_failure: boolean indicating whether to fallback to a restart if the
|
||||
reload fails.
|
||||
"""
|
||||
try:
|
||||
return _systemctl("reload", service_name)
|
||||
except SystemdError:
|
||||
if restart_on_failure:
|
||||
return _systemctl("restart", service_name)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def service_pause(service_name: str) -> bool:
|
||||
"""Pause a system service.
|
||||
|
||||
Stop it, and prevent it from starting again at boot.
|
||||
|
||||
Args:
|
||||
service_name: the name of the service to pause
|
||||
"""
|
||||
_systemctl("disable", service_name, now=True)
|
||||
_systemctl("mask", service_name)
|
||||
|
||||
if not service_running(service_name):
|
||||
return True
|
||||
|
||||
raise SystemdError("Attempted to pause '{}', but it is still running.".format(service_name))
|
||||
|
||||
|
||||
def service_resume(service_name: str) -> bool:
|
||||
"""Resume a system service.
|
||||
|
||||
Re-enable starting again at boot. Start the service.
|
||||
|
||||
Args:
|
||||
service_name: the name of the service to resume
|
||||
"""
|
||||
_systemctl("unmask", service_name)
|
||||
_systemctl("enable", service_name, now=True)
|
||||
|
||||
if service_running(service_name):
|
||||
return True
|
||||
|
||||
raise SystemdError("Attempted to resume '{}', but it is not running.".format(service_name))
|
||||
|
||||
|
||||
def daemon_reload() -> bool:
|
||||
"""Reload systemd manager configuration."""
|
||||
return _systemctl("daemon-reload")
|
|
@ -58,13 +58,10 @@ from charmhelpers.core.host import (
|
|||
cmp_pkgrevno)
|
||||
from charmhelpers.fetch import (
|
||||
apt_install,
|
||||
apt_update,
|
||||
apt_purge,
|
||||
filter_installed_packages,
|
||||
add_source,
|
||||
get_upstream_version,
|
||||
)
|
||||
from charmhelpers.payload.execd import execd_preinstall
|
||||
from charmhelpers.contrib.openstack.alternatives import install_alternative
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
clear_unit_paused,
|
||||
|
@ -158,25 +155,6 @@ def check_for_upgrade():
|
|||
level=ERROR)
|
||||
|
||||
|
||||
@hooks.hook('install.real')
|
||||
@harden()
|
||||
def install():
|
||||
execd_preinstall()
|
||||
add_source(config('source'), config('key'))
|
||||
apt_update(fatal=True)
|
||||
apt_install(packages=ceph.determine_packages(), fatal=True)
|
||||
rm_packages = ceph.determine_packages_to_remove()
|
||||
if rm_packages:
|
||||
apt_purge(packages=rm_packages, fatal=True)
|
||||
try:
|
||||
# we defer and explicitly run `ceph-create-keys` from
|
||||
# add_keyring_to_ceph() as part of bootstrap process
|
||||
# LP: #1719436.
|
||||
service_pause('ceph-create-keys')
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
def get_ceph_context():
|
||||
networks = get_networks('ceph-public-network')
|
||||
public_network = ', '.join(networks)
|
||||
|
|
26
src/charm.py
26
src/charm.py
|
@ -2,16 +2,40 @@
|
|||
|
||||
from ops.main import main
|
||||
|
||||
import charms.operator_libs_linux.v0.apt as apt
|
||||
import charms.operator_libs_linux.v1.systemd as systemd
|
||||
|
||||
import ops_openstack.core
|
||||
import charms_ceph.utils as ceph
|
||||
|
||||
import ceph_hooks as hooks
|
||||
|
||||
|
||||
class CephMonCharm(ops_openstack.core.OSBaseCharm):
|
||||
|
||||
release = 'quincy'
|
||||
|
||||
PACKAGES = [
|
||||
'ceph', 'gdisk',
|
||||
'radosgw', 'lvm2', 'parted', 'smartmontools',
|
||||
]
|
||||
|
||||
# General charm control callbacks.
|
||||
|
||||
# TODO: Figure out how to do hardening in an operator-framework
|
||||
# world
|
||||
def on_install(self, event):
|
||||
hooks.install()
|
||||
self.install_pkgs()
|
||||
rm_packages = ceph.determine_packages_to_remove()
|
||||
if rm_packages:
|
||||
apt.remove_package(packages=rm_packages, fatal=True)
|
||||
try:
|
||||
# we defer and explicitly run `ceph-create-keys` from
|
||||
# add_keyring_to_ceph() as part of bootstrap process
|
||||
# LP: #1719436.
|
||||
systemd.service_pause('ceph-create-keys')
|
||||
except systemd.SystemdError:
|
||||
pass
|
||||
|
||||
def on_config(self, event):
|
||||
hooks.config_changed()
|
||||
|
|
Loading…
Reference in New Issue