cephadm: log to file

Log configuration improved adding a log file with debug level.

Signed-off-by: Juan Miguel Olmo Martínez <jolmomar@redhat.com>
This commit is contained in:
Juan Miguel Olmo Martínez 2020-08-24 13:05:31 +02:00
parent 1e4e394699
commit 81a7df0498
No known key found for this signature in database
GPG Key ID: F38428F191BEBAB1
2 changed files with 75 additions and 36 deletions
src/cephadm

View File

@ -44,6 +44,7 @@ import fcntl
import ipaddress
import json
import logging
from logging.config import dictConfig
import os
import platform
import pwd
@ -93,6 +94,36 @@ cached_stdin = None
DATEFMT = '%Y-%m-%dT%H:%M:%S.%f'
# Log and console output config
logging_config = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'cephadm': {
'format': '%(asctime)s %(levelname)s %(message)s'
},
},
'handlers': {
'console':{
'level':'INFO',
'class':'logging.StreamHandler',
},
'log_file': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'cephadm',
'filename': '%s/cephadm.log' % LOG_DIR,
'maxBytes': 1024000,
'backupCount': 1,
}
},
'loggers': {
'': {
'level': 'DEBUG',
'handlers': ['console', 'log_file'],
}
}
}
class termcolor:
yellow = '\033[93m'
@ -840,7 +871,8 @@ def call(command, # type: List[str]
assert False
except (IOError, OSError):
pass
logger.debug(desc + ':profile rt=%s, stop=%s, exit=%s, reads=%s'
if verbose:
logger.debug(desc + ':profile rt=%s, stop=%s, exit=%s, reads=%s'
% (time.time()-start_time, stop, process.poll(), reads))
returncode = process.wait()
@ -2572,7 +2604,7 @@ def command_bootstrap():
raise Error('hostname is a fully qualified domain name (%s); either fix (e.g., "sudo hostname %s" or similar) or pass --allow-fqdn-hostname' % (hostname, hostname.split('.')[0]))
mon_id = args.mon_id or hostname
mgr_id = args.mgr_id or generate_service_id()
logging.info('Cluster fsid: %s' % fsid)
logger.info('Cluster fsid: %s' % fsid)
ipv6 = False
l = FileLock(fsid)
@ -3471,6 +3503,7 @@ def command_list_networks():
def command_ls():
# type: () -> None
ls = list_daemons(detail=not args.no_detail,
legacy_dir=args.legacy_dir)
print(json.dumps(ls, indent=4))
@ -3597,7 +3630,7 @@ def list_daemons(detail=True, legacy_dir=None):
version = err.split(' ')[2]
seen_versions[image_id] = version
else:
logging.warning('version for unknown daemon type %s' % daemon_type)
logger.warning('version for unknown daemon type %s' % daemon_type)
else:
vfile = os.path.join(data_dir, fsid, j, 'unit.image') # type: ignore
try:
@ -4296,7 +4329,7 @@ class Packager(object):
def query_shaman(self, distro, distro_version, branch, commit):
# query shaman
logging.info('Fetching repo metadata from shaman and chacra...')
logger.info('Fetching repo metadata from shaman and chacra...')
shaman_url = 'https://shaman.ceph.com/api/repos/ceph/{branch}/{sha1}/{distro}/{distro_version}/repo/?arch={arch}'.format(
distro=distro,
distro_version=distro_version,
@ -4307,13 +4340,13 @@ class Packager(object):
try:
shaman_response = urlopen(shaman_url)
except HTTPError as err:
logging.error('repository not found in shaman (might not be available yet)')
logger.error('repository not found in shaman (might not be available yet)')
raise Error('%s, failed to fetch %s' % (err, shaman_url))
try:
chacra_url = shaman_response.geturl()
chacra_response = urlopen(chacra_url)
except HTTPError as err:
logging.error('repository not found in chacra (might not be available yet)')
logger.error('repository not found in chacra (might not be available yet)')
raise Error('%s, failed to fetch %s' % (err, chacra_url))
return chacra_response.read().decode('utf-8')
@ -4350,11 +4383,11 @@ class Apt(Packager):
def add_repo(self):
url, name = self.repo_gpgkey()
logging.info('Installing repo GPG key from %s...' % url)
logger.info('Installing repo GPG key from %s...' % url)
try:
response = urlopen(url)
except HTTPError as err:
logging.error('failed to fetch GPG repo key from %s: %s' % (
logger.error('failed to fetch GPG repo key from %s: %s' % (
url, err))
raise Error('failed to fetch GPG key')
key = response.read().decode('utf-8')
@ -4371,7 +4404,7 @@ class Apt(Packager):
content = self.query_shaman(self.distro, self.distro_codename, self.branch,
self.commit)
logging.info('Installing repo file at %s...' % self.repo_path())
logger.info('Installing repo file at %s...' % self.repo_path())
with open(self.repo_path(), 'w') as f:
f.write(content)
@ -4379,28 +4412,28 @@ class Apt(Packager):
for name in ['autobuild', 'release']:
p = '/etc/apt/trusted.gpg.d/ceph.%s.gpg' % name
if os.path.exists(p):
logging.info('Removing repo GPG key %s...' % p)
logger.info('Removing repo GPG key %s...' % p)
os.unlink(p)
if os.path.exists(self.repo_path()):
logging.info('Removing repo at %s...' % self.repo_path())
logger.info('Removing repo at %s...' % self.repo_path())
os.unlink(self.repo_path())
def install(self, ls):
logging.info('Installing packages %s...' % ls)
logger.info('Installing packages %s...' % ls)
call_throws(['apt', 'install', '-y'] + ls)
def install_podman(self):
if self.distro == 'ubuntu':
logging.info('Setting up repo for pdoman...')
logger.info('Setting up repo for pdoman...')
self.install(['software-properties-common'])
call_throws(['add-apt-repository', '-y', 'ppa:projectatomic/ppa'])
call_throws(['apt', 'update'])
logging.info('Attempting podman install...')
logger.info('Attempting podman install...')
try:
self.install(['podman'])
except Error as e:
logging.info('Podman did not work. Falling back to docker...')
logger.info('Podman did not work. Falling back to docker...')
self.install(['docker.io'])
@ -4514,7 +4547,7 @@ class YumDnf(Packager):
self.branch,
self.commit)
logging.info('Writing repo to %s...' % self.repo_path())
logger.info('Writing repo to %s...' % self.repo_path())
with open(self.repo_path(), 'w') as f:
f.write(content)
@ -4611,7 +4644,7 @@ class Zypper(Packager):
self.branch,
self.commit)
logging.info('Writing repo to %s...' % self.repo_path())
logger.info('Writing repo to %s...' % self.repo_path())
with open(self.repo_path(), 'w') as f:
f.write(content)
@ -4684,7 +4717,7 @@ def get_ipv4_address(ifname):
offset,
struct.pack('256s', bytes(ifname[:15], 'utf-8'))
)[20:24])
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
addr = _extract(s, 35093) # '0x8915' = SIOCGIFADDR
@ -4692,7 +4725,7 @@ def get_ipv4_address(ifname):
except OSError:
# interface does not have an ipv4 address
return ''
dec_mask = sum([bin(int(i)).count('1')
for i in dq_mask.split('.')])
return '{}/{}'.format(addr, dec_mask)
@ -4720,8 +4753,8 @@ def get_ipv6_address(ifname):
def bytes_to_human(num, mode='decimal'):
# type: (float, str) -> str
"""Convert a bytes value into it's human-readable form.
"""Convert a bytes value into it's human-readable form.
:param num: number, in bytes, to convert
:param mode: Either decimal (default) or binary to determine divisor
:returns: string representing the bytes value in a more readable format
@ -4745,7 +4778,7 @@ def bytes_to_human(num, mode='decimal'):
def read_file(path_list, file_name=''):
# type: (List[str], str) -> str
"""Returns the content of the first file found within the `path_list`
:param path_list: list of file paths to search
:param file_name: optional file_name to be applied to a file path
:returns: content of the file or 'Unknown'
@ -4993,7 +5026,7 @@ class HostFacts():
if not os.path.exists(nic_path):
continue
for iface in os.listdir(nic_path):
lower_devs_list = [os.path.basename(link.replace("lower_", "")) for link in glob(os.path.join(nic_path, iface, "lower_*"))]
upper_devs_list = [os.path.basename(link.replace("upper_", "")) for link in glob(os.path.join(nic_path, iface, "upper_*"))]
@ -5070,7 +5103,7 @@ class HostFacts():
# type: () -> int
"""Determine the memory installed (kb)"""
return self._get_mem_data('MemTotal')
@property
def memory_free_kb(self):
# type: () -> int
@ -5117,7 +5150,7 @@ class HostFacts():
# type: () -> float
"""Return the current time as Epoch seconds"""
return time.time()
@property
def system_uptime(self):
# type: () -> float
@ -5136,7 +5169,7 @@ class HostFacts():
for selinux_path in HostFacts._selinux_path_list:
if os.path.exists(selinux_path):
selinux_config = read_file([selinux_path]).splitlines()
security['type'] = 'SELinux'
security['type'] = 'SELinux'
for line in selinux_config:
if line.strip().startswith('#'):
continue
@ -5171,7 +5204,7 @@ class HostFacts():
summary_str = ",".join(["{} {}".format(v, k) for k, v in summary.items()])
security = {**security, **summary} # type: ignore
security['description'] += "({})".format(summary_str)
return security
if os.path.exists('/sys/kernel/security/lsm'):
@ -5196,7 +5229,7 @@ class HostFacts():
"""Return the attributes of this HostFacts object as json"""
data = {k: getattr(self, k) for k in dir(self)
if not k.startswith('_') and
isinstance(getattr(self, k),
isinstance(getattr(self, k),
(float, int, str, list, dict, tuple))
}
return json.dumps(data, indent=2, sort_keys=True)
@ -5735,18 +5768,26 @@ def _parse_args(av):
if __name__ == "__main__":
# Logger configuration
if not os.path.exists(LOG_DIR):
os.makedirs(LOG_DIR)
dictConfig(logging_config)
logger = logging.getLogger()
# allow argv to be injected
try:
av = injected_argv # type: ignore
except NameError:
av = sys.argv[1:]
logger.debug("%s\ncephadm %s" % ("-" * 80, av))
args = _parse_args(av)
# More verbose console output
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('cephadm')
for handler in logger.handlers:
if handler.name == "console":
handler.setLevel(logging.DEBUG)
# root?
if os.geteuid() != 0:

View File

@ -1,18 +1,16 @@
# type: ignore
import argparse
import mock
from mock import patch
import os
import sys
import unittest
import pytest
if sys.version_info >= (3, 3):
with patch('builtins.open', create=True):
from importlib.machinery import SourceFileLoader
cd = SourceFileLoader('cephadm', 'cephadm').load_module()
else:
import imp
cd = imp.load_source('cephadm', 'cephadm')
class TestCephAdm(object):
def test_is_fsid(self):