wadebug/wa_actions/implementations/check_software_version.py (119 lines of code) (raw):

# Copyright (c) Facebook, Inc. and its affiliates. # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. from __future__ import absolute_import, division, print_function, unicode_literals from collections import defaultdict from datetime import datetime from wadebug import results from wadebug.wa_actions import docker_utils from wadebug.wa_actions.base import WAAction class CheckSoftwareVersion(WAAction): user_facing_name = "check_software_version" short_description = "Action to test whether software version is up-to-date" @classmethod def _run(cls, config, *args, **kwargs): errors = [] warnings = [] expiration_date_map = docker_utils.get_expiration_map() def get_all_running_wa_containers(): wa_containers = docker_utils.get_wa_containers() versions_to_wa_containers_dict = defaultdict(lambda: defaultdict(list)) for wa_container in wa_containers: container = wa_container.container container_type = wa_container.get_container_type() if docker_utils.is_container_running(container): if wa_container.is_webapp() or wa_container.is_coreapp(): version = docker_utils.get_wa_version_from_container(container) versions_to_wa_containers_dict[version][container_type].append( container ) return versions_to_wa_containers_dict def is_valid_version(version, wa_containers_dict): containers = [] for container in wa_containers_dict.values(): containers.extend(container) valid_version = True cur = datetime.utcnow().strftime(docker_utils.DATE_FORMAT) try: days_delta = days_between(cur, expiration_date_map[version[0]]) if days_delta < 0: valid_version = False error_str = ( "{}: Current version of your container {} has expired on {} UTC" ) for container in containers: errors.append( error_str.format( container.name, version[1], expiration_date_map[version[0]], ) ) elif days_delta < 7: warnings_str = "{}: Current version of your software ({}) " "is expiring on {} UTC, please consider upgrading soon" for container in containers: warnings.append( warnings_str.format( container.name, version[1], expiration_date_map[version[0]], ) ) except KeyError: valid_version = False error_str = ( "{}: Current version of your container ({}) is deprecated or " ) "wadebug tool is not up-to-date" for container in containers: errors.append(error_str.format(container.name, version[1])) return valid_version running_wa_containers = get_all_running_wa_containers() valid_versions = [] for key, value in running_wa_containers.items(): if len(value[docker_utils.WA_COREAPP_CONTAINER_TAG]) != len( value[docker_utils.WA_WEBAPP_CONTAINER_TAG] ): errors.append( "Number of coreapp containers for version {} is not same as " "number of webapp containers".format(key) ) elif is_valid_version(key, value): valid_versions.append(key[1]) if len(valid_versions) > 1: warnings.append( "More than one set of valid software versions({}) are running. " "It may be fine, but worth noticing.".format(valid_versions) ) if errors: error_str = "Error Message: {}\n" warning_str = "Warning Message: {}\n" return results.Problem( cls, "Some of your WhatsApp container versions are expired " "or there is mismatch between versions" " of coreapp and webapp", "{}\n{}".format( "\n".join([error_str.format(e) for e in errors]), "\n".join([warning_str.format(w) for w in warnings]), ), "Please find the following link to find latest version: " "https://developers.facebook.com/docs/whatsapp/changelog\n" "and please find upgrade instructions here:" "https://developers.facebook.com/docs/whatsapp/guides/installation\n", ) if warnings: warning_str = "Warning Message: {}\n" return results.Warning( cls, "Some of your WhatsApp conatiners are nearing expiration or " "more than one valid version is running", "\n".join([warning_str.format(w) for w in warnings]), "Please find the following link to find latest version: " "https://developers.facebook.com/docs/whatsapp/changelog\n" "and please find upgrade instructions here:" "https://developers.facebook.com/docs/whatsapp/guides/installation\n", ) return results.OK(cls) def days_between(d1, d2): d1 = datetime.strptime(d1, docker_utils.DATE_FORMAT) d2 = datetime.strptime(d2, docker_utils.DATE_FORMAT) return (d2 - d1).days