]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
cephadm: include timestamps for started, deploy
authorSage Weil <sage@redhat.com>
Wed, 4 Mar 2020 14:48:58 +0000 (08:48 -0600)
committerSage Weil <sage@redhat.com>
Thu, 5 Mar 2020 12:42:26 +0000 (06:42 -0600)
started == when the container started
deployed == when the container was (most recently) (re)deployed

Signed-off-by: Sage Weil <sage@redhat.com>
src/cephadm/cephadm

index 365528903471c4f64f9ea62505cfc211baea21ef..1180eb5ce7299d4d01dd6b2bc755608e86f323a4 100755 (executable)
@@ -35,6 +35,7 @@ You can invoke cephadm in two ways:
 """
 
 import argparse
+import datetime
 import fcntl
 import json
 import logging
@@ -80,6 +81,8 @@ else:
 container_path = ''
 cached_stdin = None
 
+DATEFMT = '%Y-%m-%dT%H:%M:%S.%f'
+
 class Error(Exception):
     pass
 
@@ -608,6 +611,53 @@ def pathify(p):
         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, ...]
@@ -2346,6 +2396,7 @@ def list_daemons(detail=True, legacy_dir=None):
                         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'
@@ -2355,14 +2406,16 @@ def list_daemons(detail=True, legacy_dir=None):
                         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)
@@ -2388,6 +2441,9 @@ def list_daemons(detail=True, legacy_dir=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