"""
import argparse
+import datetime
import fcntl
import json
import logging
container_path = ''
cached_stdin = None
+DATEFMT = '%Y-%m-%dT%H:%M:%S.%f'
+
class Error(Exception):
pass
return os.path.join(os.getcwd(), p)
return p
+def get_file_timestamp(fn):
+ try:
+ mt = os.path.getmtime(fn)
+ return datetime.datetime.fromtimestamp(
+ mt, tz=datetime.timezone.utc
+ ).strftime(DATEFMT)
+ except Exception as e:
+ return None
+
+def try_convert_datetime(s):
+ # This is super irritating because
+ # 1) podman and docker use different formats
+ # 2) python's strptime can't parse either one
+ #
+ # I've seen:
+ # docker 18.09.7: 2020-03-03T09:21:43.636153304Z
+ # podman 1.7.0: 2020-03-03T15:52:30.136257504-06:00
+ # 2020-03-03 15:52:30.136257504 -0600 CST
+ # (In the podman case, there is a different string format for
+ # 'inspect' and 'inspect --format {{.Created}}'!!)
+
+ # In *all* cases, the 9 digit second precision is too much for
+ # python's strptime. Shorten it to 6 digits.
+ p = re.compile(r'(\.\d\d\d\d\d\d)\d\d\d')
+ s = p.sub(r'\1', s)
+
+ # replace trailling Z with -0000, since (on python 3.6.8) it won't parse
+ if s and s[-1] == 'Z':
+ s = s[:-1] + '-0000'
+
+ # cut off the redundnat 'CST' part that strptime can't parse, if
+ # present.
+ v = s.split(' ')
+ s = ' '.join(v[0:3])
+
+ # try parsing with several format strings
+ fmts = [
+ '%Y-%m-%dT%H:%M:%S.%f%z',
+ '%Y-%m-%d %H:%M:%S.%f %z',
+ ]
+ for f in fmts:
+ try:
+ # return timestamp normalized to UTC, rendered as DATEFMT.
+ return datetime.datetime.strptime(s, f).astimezone(tz=datetime.timezone.utc).strftime(DATEFMT)
+ except ValueError:
+ pass
+ return None
def get_podman_version():
# type: () -> Tuple[int, ...]
image_name = None
image_id = None
version = None
+ start_stamp = None
if 'podman' in container_path and get_podman_version() < (1, 6, 2):
image_field = '.ImageID'
out, err, code = call(
[
container_path, 'inspect',
- '--format', '{{.Id}},{{.Config.Image}},{{%s}},{{index .Config.Labels "io.ceph.version"}}' % image_field,
+ '--format', '{{.Id}},{{.Config.Image}},{{%s}},{{.Created}},{{index .Config.Labels "io.ceph.version"}}' % image_field,
'ceph-%s-%s' % (fsid, j)
],
verbose_on_failure=False)
if not code:
- (container_id, image_name, image_id, version) = out.strip().split(',')
+ (container_id, image_name, image_id, start,
+ version) = out.strip().split(',')
image_id = normalize_container_id(image_id)
daemon_type = name.split('.', 1)[0]
+ start_stamp = try_convert_datetime(start)
if daemon_type in Ceph.daemons:
if not version or '.' not in version:
version = seen_versions.get(image_id, None)
i['container_image_name'] = image_name
i['container_image_id'] = image_id
i['version'] = version
+ i['started'] = start_stamp
+ i['deployed'] = get_file_timestamp(
+ os.path.join(data_dir, fsid, j, 'unit.image'))
ls.append(i)
# /var/lib/rook