Пример #1
0
def fix_message_dict(mdict, allow_old_format=False):
    if mdict is None:
        return None

    if not isinstance(mdict, dict):
        raise HsException("Message is not a dictionary: \"%s\"<%s>" %
                          (mdict, type(mdict)))

    for prefix in ("start", "stop"):
        found = False
        for suffix in ("ticks", "time"):
            if prefix + "_" + suffix in mdict:
                found = True
                break
        if not found:
            raise HsException("Dictionary is missing %s_time or %s_ticks" %
                              (prefix, prefix))

    # check for mandatory fields
    if "msgtype" not in mdict:
        mdict["msgtype"] = INITIAL
    if "request_id" not in mdict:
        if mdict["msgtype"] != INITIAL:
            raise HsException("No request ID found in %s" % str(mdict))
        mdict["request_id"] = ID.generate()
    if "copy_dir" not in mdict:
        mdict["copy_dir"] = None
    if "extract" not in mdict:
        mdict["extract"] = False
    if "hubs" not in mdict:
        mdict["hubs"] = ""

    return mdict
Пример #2
0
    def __insert_detail(self, request_id, username, prefix, start_ticks,
                        stop_ticks, dest_dir, hubs, extract, phase):
        if start_ticks is None:
            raise HsException("Start time cannot be None")
        elif not isinstance(start_ticks, numbers.Number):
            raise HsException("Start time must be number, not %s(%s)" %
                              (type(start_ticks), str(start_ticks)))
        if stop_ticks is None:
            raise HsException("Stop time cannot be None")
        elif not isinstance(stop_ticks, numbers.Number):
            raise HsException("Stop time must be number, not %s(%s)" %
                              (type(stop_ticks), str(stop_ticks)))

        if self.__sqlconn is None:
            self.__sqlconn = self.__open_database()
        with self.__sqlconn:
            cursor = self.__sqlconn.cursor()

            # add details to DB
            cursor.execute(
                "insert or replace into request_details"
                "(id, username, prefix, start_time, stop_time,"
                " destination, hubs, extract, phase)"
                " values (?, ?, ?, ?, ?, ?, ?, ?, ?)",
                (request_id, username, prefix, start_ticks, stop_ticks,
                 dest_dir, "" if hubs is None else hubs, 1 if extract else 0,
                 phase))

            # add details to cache
            with self.__reqlock:
                self.__requests[request_id][self.DETAIL_KEY] \
                    = (username, prefix, start_ticks, stop_ticks, dest_dir,
                       hubs, extract, phase)
Пример #3
0
def ticks_to_utc(ticks):
    "Convert an integral DAQ tick value to a time object"
    if ticks is None:
        raise HsException("No tick value specified")
    if not isinstance(ticks, numbers.Number):
        raise HsException("Tick value %s should be number, not %s" %
                          (ticks, type(ticks).__name__))
    return jan1_by_year() + datetime.timedelta(seconds=ticks / 1E10)
Пример #4
0
    def move_file(cls, src, dst):
        if not os.path.exists(dst):
            raise HsException("Directory \"%s\" does not exist,"
                              " cannot move \"%s\"" % (dst, src))

        try:
            shutil.move(src, dst)
        except Exception as sex:
            raise HsException("Cannot move \"%s\" to \"%s\": %s" %
                              (src, dst, sex))
Пример #5
0
    def hardlink(cls, filename, targetdir):
        path = os.path.join(targetdir, os.path.basename(filename))
        if os.path.exists(path):
            raise HsException("File \"%s\" already exists" % path)

        try:
            os.link(filename, path)
        except Exception as err:
            raise HsException("Cannot link \"%s\" to \"%s\": %s" %
                              (filename, targetdir, err))
Пример #6
0
    def copy(self, source_list, request=None, update_status=None):
        if source_list is None or len(source_list) == 0:
            raise HsException("No source specified")

        failed = []
        for src in source_list:
            rtncode = self.copy_one(src)
            if rtncode != 0:
                logging.error("failed to copy %s to \"%s\" (rtn=%d,"
                              " unknown=%d)", src, self.__target, rtncode,
                              self.__unknown_count)
                failed.append(src)
                self.__unknown_count = 0

            if update_status is not None and request is not None:
                update_status(request.copy_dir, request.destination_dir,
                              HsMessage.WORKING)

        result = self.summarize()
        if result is not None:
            (_, size, _, _, _) = result
            if self.__size is None:
                self.__size = size
            else:
                self.__size += size

        return failed
Пример #7
0
    def split_rsync_path(self, rsync_path):
        """
        Return a tuple containing (user, host, path) pieces of the rsync path,
        filling in default values for any missing pieces
        """
        if rsync_path is None:
            user = None
            host = None
            path = self.DEFAULT_COPY_PATH
        else:
            mtch = self.COPY_PATH_PAT.match(rsync_path)
            if mtch is None:
                raise HsException("Bad copy path \"%s\"" % rsync_path)

            user = mtch.group(2)
            host = mtch.group(4)
            path = mtch.group(5)

        if user is None:
            user = self.rsync_user

        if host is None:
            host = self.rsync_host

        return (user, host, path)
Пример #8
0
    def __write_tarfile_internal(sourcedir, sourcefiles, tarname):
        extra = ""
        if tarname.endswith(".gz") or tarname.endswith(".tgz"):
            extra = ":gz"
        elif tarname.endswith(".bz2"):
            extra = ":bz2"

        try:
            tar = tarfile.open(tarname, "w" + extra)
        except Exception as err:
            raise HsException("Cannot create \"%s\" in \"%s\": %s" %
                              (tarname, sourcedir, err))

        if isinstance(sourcefiles, list):
            sourcelist = sourcefiles
        else:
            sourcelist = [sourcefiles, ]

        try:
            for fnm in sourcelist:
                try:
                    tar.add(fnm)
                except Exception as err:
                    logging.error("Failed to add \"%s\" to \"%s\": %s",
                                  fnm, os.path.join(sourcedir, tarname), err)
        finally:
            tar.close()
Пример #9
0
def assemble_email_dict(address_list,
                        header,
                        message,
                        description="HsInterface Data Request",
                        prio=2,
                        short_subject=True,
                        quiet=True):
    if address_list is None or len(address_list) == 0:
        raise HsException("No addresses specified")

    notifies = []
    for email in address_list:
        ndict = {
            "receiver": email,
            "notifies_txt": message,
            "notifies_header": header,
        }
        notifies.append(ndict)

    now = datetime.datetime.now()
    return {
        "service": "HSiface",
        "varname": "alert",
        "prio": prio,
        "time": now.strftime("%Y-%m-%d %H:%M:%S"),
        "value": {
            "condition": header,
            "desc": description,
            "notifies": notifies,
            "short_subject": "true" if short_subject else "false",
            "quiet": "true" if quiet else "false",
        },
    }
Пример #10
0
    def __init__(self, cmd=None, rmt_user=None, rmt_host=None,
                 rmt_dir=None, rmt_subdir=None, make_remote_dir=False):
        if rmt_host is None or rmt_host == "":
            raise HsException("No remote host specified")
        if rmt_dir is None or rmt_dir == "":
            raise HsException("No remote directory specified")

        if make_remote_dir:
            self.make_remote_directory(rmt_user, rmt_host, rmt_dir)

        self.__target = self.build_target(rmt_user, rmt_host, rmt_dir,
                                          rmt_subdir)
        self.__cmd = cmd

        self.__size = None
        self.__unknown_count = 0
Пример #11
0
def dict_to_object(xdict, expected_fields, objtype):
    """
    Convert a dictionary (which must have the expected keys) into
    a named tuple
    """
    if not isinstance(xdict, dict):
        raise HsException("Bad object \"%s\"<%s>" % (xdict, type(xdict)))

    missing = []
    for k in expected_fields:
        if k not in xdict:
            missing.append(k)

    if len(missing) > 0:
        raise HsException("Missing fields %s from %s" %
                          (tuple(missing), xdict))

    return namedtuple(objtype, list(xdict.keys()))(**xdict)
Пример #12
0
    def __receive(cls, sock):
        mdict = sock.recv_json()
        if mdict is None:
            return None

        if not isinstance(mdict, dict):
            raise HsException("Received %s(%s), not dictionary" %
                              (mdict, type(mdict).__name__))

        return HsMessage.from_dict(mdict)
Пример #13
0
def string_to_ticks(timestr, is_ns=False):
    "Convert a time string to an integral DAQ tick value"
    if timestr is None:
        raise HsException("Found null value for start/stop time in %s" %
                          (timestr, ))

    multiplier = 10 if is_ns else 1
    if isinstance(timestr, numbers.Number):
        return int(timestr * multiplier)

    if isinstance(timestr, (str, unicode)):
        if timestr.isdigit():
            try:
                return int(timestr) * multiplier
            except:
                raise HsException("Cannot convert \"%s\" to ticks" %
                                  (timestr, ))

        try:
            utc = datetime.datetime.strptime(timestr, TIME_FORMAT)
        except ValueError:
            # Python date parser can only handle milliseconds
            if timestr.find(".") > 0:
                short = re.sub(r"(\.\d{6})\d+", r"\1", timestr)
                try:
                    utc = datetime.datetime.strptime(short, TIME_FORMAT)
                except:
                    raise HsException("Cannot convert \"%s\" to datetime" %
                                      (timestr, ))
            elif TIME_FORMAT.endswith(".%f"):
                shortfmt = TIME_FORMAT[:-3]
                try:
                    utc = datetime.datetime.strptime(timestr, shortfmt)
                except:
                    raise HsException("Cannot convert \"%s\" to datetime" %
                                      (timestr, ))

        return utc_to_ticks(utc)

    raise HsException("Cannot convert %s(%s) to ticks" %
                      (type(timestr).__name__, timestr))
Пример #14
0
def split_rsync_host_and_path(rsync_path):
    "Remove leading 'user@host:' from rsync path"
    if not isinstance(rsync_path, (str, unicode)):
        raise HsException("Illegal rsync path \"%s\"<%s>" %
                          (rsync_path, type(rsync_path)))

    parts = rsync_path.split(":", 1)
    if len(parts) > 1 and parts[0].find("/") < 0:
        return parts

    # either no embedded colons or colons are part of the path
    return "", rsync_path
Пример #15
0
    def receive_request(self, sock):
        """
        Receive the next request, validate it,
        then push it to the processor thread
        """
        req_dict = sock.recv_json()
        if req_dict is None:
            return

        if not isinstance(req_dict, dict):
            raise HsException("JSON message should be a dict: \"%s\"<%s>" %
                              (req_dict, type(req_dict)))

        if "ping" in req_dict:
            # reply to ping from sender
            self.__ping_watcher.update()
            self.sender.send_json({"pingback": self.fullhost})
            return

        # ensure 'start_time' and 'stop_time' are present and numbers
        for tkey in ("start_ticks", "stop_ticks"):
            if tkey not in req_dict:
                raise HsException("Request does not contain '%s'" % (tkey, ))
            elif not isinstance(req_dict[tkey], numbers.Number):
                raise HsException("Request '%s' should be a number, not %s" %
                                  (tkey, type(req_dict[tkey]).__name__))

        # ensure 'extract' field is present and is a boolean value
        req_dict["extract"] = "extract" in req_dict and \
            req_dict["extract"] is True

        alert_flds = ("request_id", "username", "start_ticks", "stop_ticks",
                      "destination_dir", "prefix", "extract")

        req = HsUtil.dict_to_object(req_dict, alert_flds, 'WorkerRequest')

        logging.info("HsWorker queued request:\n"
                     "%s\nfrom Publisher", str(req))

        self.__req_thread.push(req)
Пример #16
0
    def process_one_message(self, sock, force_spade=False):
        mdict = sock.recv_json()
        if mdict is None:
            return False

        if not isinstance(mdict, dict):
            raise HsException("Received %s(%s), not dictionary" %
                              (mdict, type(mdict).__name__))

        if sock == self.__reporter and "pingback" in mdict:
            self.__ping_manager.add_reply(mdict["pingback"])
            return True

        error = True
        try:
            msg = HsMessage.from_dict(mdict, allow_old_format=True)
            if msg is None:
                return False
            error = False
        except HsException:
            raise
        except:
            logging.exception("Cannot receive message from %s",
                              sock.identity)

        found = False
        if not error:
            try:
                self.__monitor.add_message(msg, force_spade)
                found = True
            except:
                logging.exception("Received bad message %s", str(msg))
                error = True

        if sock == self.__alert_socket:
            if error:
                rtnmsg = "ERROR"
            else:
                rtnmsg = "DONE"

            # reply to requester:
            #  added \0 to fit C/C++ zmq message termination
            try:
                answer = sock.send(rtnmsg + "\0")
                if answer is not None:
                    logging.error("Failed sending %s to requester: %s",
                                  rtnmsg, answer)
            except zmq.ZMQError:
                logging.exception("Cannot return \"%s\" to %s", rtnmsg,
                                  sock.identity)

        return found
Пример #17
0
 def build_target(self, rmt_user, rmt_host, rmt_dir, rmt_subdir):
     if self.__use_daemon:
         # rsync daemon maps hitspool/ to /mnt/data/pdaqlocal/HsDataCopy/
         target = '%s@%s::hitspool/%s/' % \
                  (rmt_user, rmt_host, rmt_subdir)
     else:
         target = rmt_dir
     if target is None or target == "":
         raise HsException("No target specified")
     if target[-1] != "/":
         # make sure `rsync` knows the target should be a directory
         target += "/"
     return target
Пример #18
0
    def __convert_message_dict(cls, olddict, live_msg=False):
        mdict = olddict.copy()

        # fix time-based fields
        for prefix in ("start", "stop"):
            key = prefix + "_ticks"
            if key not in mdict:
                raise HsException("Message is missing \"%s_ticks\"" %
                                  (prefix, ))

            if not isinstance(mdict[key], numbers.Number):
                raise HsException("Message field %s type is %s, not number" %
                                  (key, type(mdict[key]).__name__))

            if live_msg:
                if key.endswith("_ticks"):
                    del mdict[key]
                mdict[prefix + "_time"] \
                    = str(DAQTime.ticks_to_utc(mdict[key]))

        # return new dictionary
        return mdict
Пример #19
0
    def __expect_live_status(cls,
                             sender,
                             mdict,
                             status=None,
                             success=None,
                             failed=None):
        # if no status was specified, use success/failed to derive it
        if status is None:
            if success is not None:
                if failed is not None:
                    status = HsUtil.STATUS_PARTIAL
                else:
                    status = HsUtil.STATUS_SUCCESS
            elif failed is not None:
                status = HsUtil.STATUS_FAIL
            else:
                raise HsException("Must specify status or success/failed")

        livedict = mdict.copy()
        # delete non-Live fields
        for fld in ("copy_dir", "host", "version", "msgtype", "extract",
                    "hubs"):
            if fld in livedict:
                del livedict[fld]

        # fix time-based fields
        for prefix in ("start", "stop"):
            tick_key = prefix + "_ticks"
            time_key = prefix + "_time"
            if tick_key in livedict:
                utc = DAQTime.ticks_to_utc(livedict[tick_key])
                livedict[time_key] = str(utc)
                del livedict[tick_key]
            elif time_key not in livedict:
                raise ValueError("Message has neither \"%s_ticks\" nor"
                                 " \"%s_time\"" % (prefix, prefix))

        # add a few Live-specific fields
        livedict["status"] = status
        livedict["update_time"] = TIME_PAT
        if success is not None:
            livedict["success"] = success
        if failed is not None:
            livedict["failed"] = failed

        sender.i3socket.add_expected_message(livedict,
                                             service="hitspool",
                                             varname="hsrequest_info",
                                             prio=1,
                                             time=TIME_PAT)
Пример #20
0
    def write_tarfile(self, sourcedir, sourcefiles, tarname):
        if not os.path.exists(sourcedir):
            raise HsException("Source directory \"%s\" does not exist" %
                              sourcedir)

        curdir = os.getcwd()

        # build tarfile inside sourcedir
        os.chdir(sourcedir)
        try:
            self.__write_tarfile_internal(sourcedir, sourcefiles, tarname)
        finally:
            # move back to original directory
            os.chdir(curdir)
Пример #21
0
    def __make_staging_dir(self, timetag):
        if self.is_cluster_sps or self.is_cluster_spts:
            tmpdir = "/mnt/data/pdaqlocal/tmp"
        else:
            tmpdir = os.path.join(self.TEST_HUB_DIR, "tmp")

        if not os.path.exists(tmpdir):
            try:
                os.makedirs(tmpdir)
            except OSError:
                # this should only happen inside unit tests
                pass

        if not os.path.isdir(tmpdir):
            raise HsException("Found non-directory at %s" % tmpdir)

        return tempfile.mkdtemp(suffix=timetag, dir=tmpdir)
Пример #22
0
    def init_logging(cls, logfile=None, basename=None, basehost=None,
                     level=logging.INFO, both=False):
        if logfile is None:
            if basename is not None and basehost is not None:
                logfile = os.path.join(HsBase.DEFAULT_LOG_PATH,
                                       "%s_%s.log" % (basename, basehost))
            elif basename is not None or basehost is not None:
                print("Not logging to file (basehost=%s, basename=%s)" %
                      (basehost, basename), file=sys.stderr)

        if logfile is not None:
            logdir = os.path.dirname(logfile)
            if not os.path.exists(logdir):
                os.makedirs(logdir)
            elif not os.path.isdir(logdir):
                raise HsException("Base log directory \"%s\" isn't"
                                  " a directory!" % logdir)

        logger = logging.getLogger()
        if len(logger.handlers) > 0:
            # any logging done before this point creates a StreamHandler
            # which causes basicConfig() to be ignored in Python 2.6
            logger.handlers = []

        if logfile is not None:
            # set up logging to file
            ten_mb = 1024 * 1024 * 10
            rot = logging.handlers.RotatingFileHandler(logfile,
                                                       maxBytes=ten_mb,
                                                       backupCount=5)
            longfmt = "%(asctime)s %(levelname)s %(message)s"
            rot.setFormatter(logging.Formatter(fmt=longfmt,
                                               datefmt="%Y-%m-%d %H:%M:%S"))
            logger.addHandler(rot)

        if logfile is None or both:
            # set up logging to console
            out = logging.StreamHandler()
            out.setFormatter(logging.Formatter("%(message)s"))
            logger.addHandler(out)

        # set log level
        logger.setLevel(level)

        return logfile
Пример #23
0
    def make_remote_directory(cls, rmt_user, rmt_host, rmt_dir):
        if rmt_user is None:
            rstr = rmt_host
        else:
            rstr = "%s@%s" % (rmt_user, rmt_host)
        cmd = ["ssh", rstr, "if [ ! -d \"%s\" ]; then mkdir -p \"%s\"; fi" %
               (rmt_dir, rmt_dir)]
        for _ in range(3):
            # this fails occasionally, possibly due to a wave of processes
            #  all trying to create subdirectories in the same directory
            rtncode = subprocess.call(cmd)
            if rtncode == 0:
                return

            # wait for this wave to die down before trying again
            time.sleep(0.1)
        raise HsException("Cannot create %s:%s (rtncode=%d)" %
                          (rstr, rmt_dir, rtncode))
Пример #24
0
    def get_watchee(self):
        """
        Depending on which machines this HsWatcher runs,
        determine the processes it is responsible to watch.
        Watcher at 2ndbuild -->  HsSender
        Watcher at expcont -->  HsPublisher
        Watcher at hub -->  HsWorker
        """
        if "2ndbuild" in self.fullhost:
            return self.create_watchee("HsSender")
        if "expcont" in self.fullhost:
            return self.create_watchee("HsPublisher")
        if "hub" in self.fullhost or "scube" in self.fullhost:
            return self.create_watchee("HsWorker")
        if "david" in self.fullhost:
            return self.create_watchee("HsWorker")

        raise HsException("Unrecognized host \"%s\"" % self.fullhost)
Пример #25
0
    def hardlink(self, filename, targetdir):
        if self.__fail_hardlink:
            raise HsException("Fake Hardlink Error")

        if len(self.__link_paths) == 0:
            raise Exception("Unexpected hardlink from \"%s\" to \"%s\"" %
                            (filename, targetdir))

        expfile, expdir, exptag = self.__link_paths.pop(0)
        if not targetdir.startswith(expdir) or \
           not targetdir.endswith(exptag):
            if filename != expfile:
                raise Exception("Expected to link \"%s\" to \"%s\", not"
                                " \"%s/*/%s\" to \"%s\"" %
                                (expfile, expdir, exptag, filename, targetdir))
            raise Exception("Expected to link \"%s\" to \"%s/*/%s\", not to"
                            " \"%s\"" % (expfile, expdir, exptag, targetdir))
        elif filename != expfile:
            raise Exception("Expected to link \"%s\" to \"%s/*/%s\", not"
                            " \"%s\"" % (expfile, expdir, exptag, filename))

        return 0
Пример #26
0
 def touch_file(cls, name, times=None):
     try:
         with open(name, "a"):
             os.utime(name, times)
     except Exception as err:
         raise HsException("Failed to 'touch' \"%s\": %s" % (name, err))
Пример #27
0
 def write_tarfile(self, sourcedir, sourcefiles, tarname):
     if self.__fail_tar_file > 0:
         self.__fail_tar_file -= 1
         raise HsException("Fake Tar Error")
Пример #28
0
 def logline(self, idx):
     if self.__loglines is None or len(self.__loglines) <= idx:
         raise HsException("Bad log index %d (%d available)" %
                           (idx, 0 if self.__loglines is None else
                            len(self.__loglines)))
     return self.__loglines[idx]
Пример #29
0
 def write_sem(self, spadedir, basename):
     if self.__fail_touch_file:
         raise HsException("Fake Touch Error")
     return "fake.sem"
Пример #30
0
    def write_meta_xml(self, spadedir, basename, start_ticks, stop_ticks):
        # use the tarfile creation time as the DIF_Creation_Date value
        tarpath = os.path.join(spadedir, basename + self.TAR_SUFFIX)
        try:
            tarstamp = os.path.getmtime(tarpath)
        except OSError:
            raise HsException("Cannot write metadata file:"
                              " %s does not exist" % tarpath)
        tartime = datetime.datetime.fromtimestamp(tarstamp)

        if stop_ticks is not None:
            stop_utc = DAQTime.ticks_to_utc(stop_ticks)
        else:
            # set stop time to the time the tarfile was written
            stop_utc = tartime
        if start_ticks is not None:
            start_utc = DAQTime.ticks_to_utc(start_ticks)
        else:
            # set start time to midnight
            start_utc = datetime.datetime(stop_utc.year, stop_utc.month,
                                          stop_utc.day)

        root = etree.Element("DIF_Plus")
        root.set("{http://www.w3.org/2001/XMLSchema-instance}"
                 "noNamespaceSchemaLocation", "IceCubeDIFPlus.xsd")

        # Metadata specification is at:
        # https://docushare.icecube.wisc.edu/dsweb/Get/Document-20546/metadata_specification.pdf
        xmldict = (
            ("DIF", (
                ("Entry_ID", basename),
                ("Entry_Title", "Hitspool_data"),
                ("Parameters",
                 "SPACE SCIENCE > Astrophysics > Neutrinos"),
                ("ISO_Topic_Category", "geoscientificinformation"),
                ("Data_Center", (
                    ("Data_Center_Name",
                     "UWI-MAD/A3RI > Antarctic Astronomy and Astrophysics"
                     " Research Institute, University of Wisconsin, Madison"),
                    ("Personnel", (
                        ("Role", "Data Center Contact"),
                        ("Email", "*****@*****.**"),
                    )),
                )),
                ("Summary", "Hitspool data"),
                ("Metadata_Name", "[CEOS IDN DIF]"),
                ("Metadata_Version", "9.4"),
                ("Personnel", (
                    ("Role", "Technical Contact"),
                    ("First_Name", "Dave"),
                    ("Last_Name", "Glowacki"),
                    ("Email", "*****@*****.**"),
                )),
                ("Sensor_Name", "ICECUBE > IceCube"),
                ("Source_Name",
                 "EXPERIMENTAL > Data with an instrumentation based"
                 " source"),
                ("DIF_Creation_Date", tartime.strftime("%Y-%m-%d")),
            )),
            ("Plus", (
                ("Start_DateTime", start_utc.strftime("%Y-%m-%dT%H:%M:%S")),
                ("End_DateTime", stop_utc.strftime("%Y-%m-%dT%H:%M:%S")),
                ("Category", "internal-system"),
                ("Subcategory", "hit-spooling"),
            )),
        )

        self.__convert_tuples_to_xml(root, xmldict)

        metaname = basename + self.META_SUFFIX
        with open(os.path.join(spadedir, metaname), "w") as out:
            line = etree.tostring(root)
            try:
                # Python3 needs to convert XML bytes to a string
                line = line.decode("utf-8")
            except:
                pass

            out.write(line)
        return metaname