Exemple #1
0
def main():

    usage = "Usage: %s <instance_name>\n" % PROGNAME

    if len(sys.argv) != 2:
        sys.stderr.write(usage)
        return 1

    instance_name = sys.argv[1]

    # WARNING: This assumes that instance names
    # are of the form prefix-id, and uses prefix to
    # determine the routekey for AMPQ
    prefix = instance_name.split('-')[0]
    routekey = "ganeti.%s.event.progress" % prefix
    amqp_client = AMQPClient(confirm_buffer=10)
    amqp_client.connect()
    amqp_client.exchange_declare(settings.EXCHANGE_GANETI, "topic")

    for msg in jsonstream(sys.stdin):
        msg['event_time'] = split_time(time.time())
        msg['instance'] = instance_name

        # log to stderr
        sys.stderr.write("[MONITOR] %s\n" % json.dumps(msg))

        # then send it over AMQP
        amqp_client.basic_publish(exchange=settings.EXCHANGE_GANETI,
                                  routing_key=routekey,
                                  body=json.dumps(msg))

    amqp_client.close()
    return 0
Exemple #2
0
def main():

    usage = "Usage: %s <instance_name>\n" % PROGNAME

    if len(sys.argv) != 2:
        sys.stderr.write(usage)
        return 1

    instance_name = sys.argv[1]

    # WARNING: This assumes that instance names
    # are of the form prefix-id, and uses prefix to
    # determine the routekey for AMPQ
    prefix = instance_name.split('-')[0]
    routekey = "ganeti.%s.event.progress" % prefix
    amqp_client = AMQPClient(confirm_buffer=10)
    amqp_client.connect()
    amqp_client.exchange_declare(settings.EXCHANGE_GANETI, "topic")

    for msg in jsonstream(sys.stdin):
        msg['event_time'] = split_time(time.time())
        msg['instance'] = instance_name

        # log to stderr
        sys.stderr.write("[MONITOR] %s\n" % json.dumps(msg))

        # then send it over AMQP
        amqp_client.basic_publish(exchange=settings.EXCHANGE_GANETI,
                                  routing_key=routekey,
                                  body=json.dumps(msg))

    amqp_client.close()
    return 0
Exemple #3
0
class Queue(object):
    """Queue.
       Required constructor parameters: hosts, exchange, client_id.
    """

    def __init__(self, **params):
        hosts = params['hosts']
        self.exchange = params['exchange']
        self.client_id = params['client_id']

        self.client = AMQPClient(hosts=hosts)
        self.client.connect()

        self.client.exchange_declare(exchange=self.exchange,
                                     type='topic')

    def send(self, message_key, user, instance, resource, value, details):
        body = Message(
            self.client_id, user, instance, resource, value, details)
        self.client.basic_publish(exchange=self.exchange,
                                  routing_key=message_key,
                                  body=json.dumps(body.__dict__))

    def close(self):
        self.client.close()
Exemple #4
0
class Queue(object):
    """Queue.
       Required constructor parameters: hosts, exchange, client_id.
    """

    def __init__(self, **params):
        hosts = params['hosts']
        self.exchange = params['exchange']
        self.client_id = params['client_id']

        self.client = AMQPClient(hosts=hosts)
        self.client.connect()

        self.client.exchange_declare(exchange=self.exchange,
                                     type='topic')

    def send(self, message_key, user, instance, resource, value, details):
        body = Message(
            self.client_id, user, instance, resource, value, details)
        self.client.basic_publish(exchange=self.exchange,
                                  routing_key=message_key,
                                  body=json.dumps(body.__dict__))

    def close(self):
        self.client.close()
Exemple #5
0
class JobFileHandler(pyinotify.ProcessEvent):
    def __init__(self, logger, cluster_name):
        pyinotify.ProcessEvent.__init__(self)
        self.logger = logger
        self.cluster_name = cluster_name

        # Set max_retries to 0 for unlimited retries.
        self.client = AMQPClient(hosts=settings.AMQP_HOSTS, confirm_buffer=25,
                                 max_retries=0, logger=logger)

        handler_logger.info("Attempting to connect to RabbitMQ hosts")

        self.client.connect()
        handler_logger.info("Connected succesfully")

        self.client.exchange_declare(settings.EXCHANGE_GANETI, type='topic')

        self.op_handlers = {"INSTANCE": self.process_instance_op,
                            "NETWORK": self.process_network_op,
                            "CLUSTER": self.process_cluster_op}
                            # "GROUP": self.process_group_op}

    def process_IN_CLOSE_WRITE(self, event):
        self.process_IN_MOVED_TO(event)

    def process_IN_MOVED_TO(self, event):
        jobfile = os.path.join(event.path, event.name)
        if not event.name.startswith("job-"):
            self.logger.debug("Not a job file: %s" % event.path)
            return

        try:
            data = utils.ReadFile(jobfile)
        except IOError:
            return

        data = serializer.LoadJson(data)
        job = jqueue._QueuedJob.Restore(None, data, False, False)

        job_id = int(job.id)

        for op in job.ops:
            op_id = op.input.OP_ID

            msg = None
            try:
                handler_fn = self.op_handlers[op_id.split('_')[1]]
                msg, routekey = handler_fn(op, job_id)
            except KeyError:
                pass

            if not msg:
                self.logger.debug("Ignoring job: %s: %s", job_id, op_id)
                continue

            # Generate a unique message identifier
            event_time = get_time_from_status(op, job)

            # Get the last line of the op log as message
            try:
                logmsg = op.log[-1][-1]
            except IndexError:
                logmsg = None

            # Add shared attributes for all operations
            msg.update({"event_time": event_time,
                        "operation": op_id,
                        "status": op.status,
                        "cluster": self.cluster_name,
                        "logmsg": logmsg,
                        "result": op.result,
                        "jobId": job_id})

            if op.status == "success":
                msg["result"] = op.result

            if op_id == "OP_INSTANCE_CREATE" and op.status == "error":
                # In case an instance creation fails send the job input
                # so that the job can be retried if needed.
                msg["job_fields"] = op.Serialize()["input"]

            msg = json.dumps(msg)

            self.logger.debug("Delivering msg: %s (key=%s)", msg, routekey)

            # Send the message to RabbitMQ
            self.client.basic_publish(settings.EXCHANGE_GANETI,
                                      routekey,
                                      msg)

    def process_instance_op(self, op, job_id):
        """ Process OP_INSTANCE_* opcodes.

        """
        input = op.input
        op_id = input.OP_ID

        instances = None
        instances = get_field(input, 'instance_name')
        if not instances:
            instances = get_field(input, 'instances')
            if not instances or len(instances) > 1:
                # Do not publish messages for jobs with no or multiple
                # instances.  Currently snf-dispatcher can not normally handle
                # these messages
                return None, None
            else:
                instances = instances[0]

        self.logger.debug("Job: %d: %s(%s) %s", job_id, op_id,
                          instances, op.status)

        job_fields = {}
        if op_id in ["OP_INSTANCE_SET_PARAMS", "OP_INSTANCE_CREATE"]:
            job_fields = {"nics": get_field(input, "nics"),
                          "disks": get_field(input, "disks"),
                          "beparams": get_field(input, "beparams")}

        msg = {"type": "ganeti-op-status",
               "instance": instances,
               "operation": op_id,
               "job_fields": job_fields}

        if ((op_id in ["OP_INSTANCE_CREATE", "OP_INSTANCE_STARTUP"] and
             op.status == "success") or
            (op_id == "OP_INSTANCE_SET_PARAMS" and
             op.status in ["success", "error", "cancelled"])):
                nics = get_instance_nics(msg["instance"], self.logger)
                msg["instance_nics"] = nics

        routekey = "ganeti.%s.event.op" % prefix_from_name(instances)

        return msg, routekey

    def process_network_op(self, op, job_id):
        """ Process OP_NETWORK_* opcodes.

        """

        input = op.input
        op_id = input.OP_ID
        network_name = get_field(input, 'network_name')

        if not network_name:
            return None, None

        self.logger.debug("Job: %d: %s(%s) %s", job_id, op_id,
                          network_name, op.status)

        job_fields = {
            'subnet': get_field(input, 'network'),
            'gateway': get_field(input, 'gateway'),
            "add_reserved_ips": get_field(input, "add_reserved_ips"),
            "remove_reserved_ips": get_field(input, "remove_reserved_ips"),
            # 'network_mode': get_field(input, 'network_mode'),
            # 'network_link': get_field(input, 'network_link'),
            'group_name': get_field(input, 'group_name')}

        msg = {'operation':    op_id,
               'type':         "ganeti-network-status",
               'network':      network_name,
               'job_fields':   job_fields}

        routekey = "ganeti.%s.event.network" % prefix_from_name(network_name)

        return msg, routekey

    def process_cluster_op(self, op, job_id):
        """ Process OP_CLUSTER_* opcodes.

        """

        input = op.input
        op_id = input.OP_ID

        self.logger.debug("Job: %d: %s %s", job_id, op_id, op.status)

        if op_id != "OP_CLUSTER_SET_PARAMS":
            # Send only modifications of cluster
            return None, None

        msg = {'operation':    op_id,
               'type':         "ganeti-cluster-status"}

        routekey = "ganeti.event.cluster"

        return msg, routekey
Exemple #6
0
class JobFileHandler(pyinotify.ProcessEvent):
    def __init__(self, logger, cluster_name):
        pyinotify.ProcessEvent.__init__(self)
        self.logger = logger
        self.cluster_name = cluster_name

        # Set max_retries to 0 for unlimited retries.
        self.client = AMQPClient(hosts=settings.AMQP_HOSTS, confirm_buffer=25,
                                 max_retries=0, logger=logger)

        logger.info("Attempting to connect to RabbitMQ hosts")

        self.client.connect()
        logger.info("Connected successfully")

        self.ganeti_master = get_ganeti_master()
        logger.debug("Ganeti Master Node: %s", self.ganeti_master)

        self.ganeti_node = get_ganeti_node()
        logger.debug("Current Ganeti Node: %s", self.ganeti_node)

        # Check if this is the master node
        logger.info("Checking if this is Ganeti Master of %s cluster: %s",
                    self.cluster_name,
                    "YES" if self.ganeti_master == self.ganeti_node else "NO")

        self.client.exchange_declare(settings.EXCHANGE_GANETI, type='topic')

        self.op_handlers = {"INSTANCE": self.process_instance_op,
                            "NETWORK": self.process_network_op,
                            "CLUSTER": self.process_cluster_op,
                            # "GROUP": self.process_group_op}
                            "TAGS": self.process_tag_op}

    def process_IN_CLOSE_WRITE(self, event):
        self.process_IN_MOVED_TO(event)

    def process_IN_MOVED_TO(self, event):
        jobfile = os.path.join(event.path, event.name)
        if not event.name.startswith("job-"):
            self.logger.debug("Not a job file: %s" % event.path)
            return

        try:
            data = utils.ReadFile(jobfile)
        except IOError:
            return

        data = serializer.LoadJson(data)
        job = jqueue._QueuedJob.Restore(None, data, False, False)

        job_id = int(job.id)

        for op in job.ops:
            op_id = op.input.OP_ID

            msg = None
            try:
                handler_fn = self.op_handlers[op_id.split('_')[1]]
                msg, routekey = handler_fn(op, job_id)
            except KeyError:
                pass

            if not msg:
                self.logger.debug("Ignoring job: %s: %s", job_id, op_id)
                continue

            # Generate a unique message identifier
            event_time = get_time_from_status(op, job)

            # Get the last line of the op log as message
            try:
                logmsg = op.log[-1][-1]
            except IndexError:
                logmsg = None

            # Add shared attributes for all operations
            msg.update({"event_time": event_time,
                        "operation": op_id,
                        "status": op.status,
                        "cluster": self.cluster_name,
                        "logmsg": logmsg,
                        "result": op.result,
                        "jobId": job_id})

            if op.status == "success":
                msg["result"] = op.result

            if op_id == "OP_INSTANCE_CREATE" and op.status == "error":
                # In case an instance creation fails send the job input
                # so that the job can be retried if needed.
                msg["job_fields"] = op.Serialize()["input"]

            # Check if this is the master node. Only the master node should
            # deliver messages to RabbitMQ.
            current_master = get_ganeti_master()
            if self.ganeti_master != current_master:
                self.logger.warning("Ganeti Master changed! New Master: %s",
                                    current_master)

                if self.ganeti_node == current_master:
                    self.logger.info("This node became Ganeti Master.")
                else:
                    self.logger.info("This node is not Ganeti Master.")

                self.ganeti_master = current_master

            msg = json.dumps(msg)

            if self.ganeti_node != self.ganeti_master:
                self.logger.debug(
                    "Ignoring msg for job: %s: %s. Reason: Not Master",
                    job_id, op_id)
                continue

            self.logger.debug("Delivering msg: %s (key=%s)", msg, routekey)

            # Send the message to RabbitMQ. Since the master node test and the
            # message delivery isn't atomic, race conditions may occur. We can
            # live with that.
            self.client.basic_publish(settings.EXCHANGE_GANETI,
                                      routekey,
                                      msg)

    def process_instance_op(self, op, job_id):
        """ Process OP_INSTANCE_* opcodes.

        """
        input = op.input
        op_id = input.OP_ID

        instances = None
        instances = get_field(input, 'instance_name')
        if not instances:
            instances = get_field(input, 'instances')
            if not instances or len(instances) > 1:
                # Do not publish messages for jobs with no or multiple
                # instances.  Currently snf-dispatcher can not normally handle
                # these messages
                return None, None
            else:
                instances = instances[0]

        self.logger.debug("Job: %d: %s(%s) %s", job_id, op_id,
                          instances, op.status)

        job_fields = {}
        if op_id in ["OP_INSTANCE_SET_PARAMS", "OP_INSTANCE_CREATE"]:
            job_fields = {"nics": get_field(input, "nics"),
                          "disks": get_field(input, "disks"),
                          "hvparams": get_field(input, "hvparams"),
                          "beparams": get_field(input, "beparams")}
        elif op_id == "OP_INSTANCE_SNAPSHOT":
            # Cyclades store the UUID of the snapshot as the 'reason' attribute
            # of the Ganeti job in order to be able to update the status of
            # the snapshot based on the result of the Ganeti job. Parse this
            # attribute and include it in the msg.
            # NOTE: This will fill the 'snapshot_info' attribute only for the
            # first disk, but this is ok because Cyclades do not issue jobs to
            # create snapshots of many disks.
            disks = get_field(input, "disks")
            if disks:
                reason = get_field(input, "reason")
                snapshot_info = None
                try:
                    reason = reason[0]
                    assert (reason[0] == "gnt:user")
                    snapshot_info = reason[1]
                    disks[0][1]["snapshot_info"] = snapshot_info
                except:
                    self.logger.warning("Malformed snapshot job '%s'", job_id)
                job_fields = {"disks": disks}

        msg = {"type": "ganeti-op-status",
               "instance": instances,
               "operation": op_id,
               "job_fields": job_fields}

        if ((op_id in ["OP_INSTANCE_CREATE", "OP_INSTANCE_STARTUP"] and
             op.status == "success") or
            (op_id in ["OP_INSTANCE_SET_PARAMS", "OP_INSTANCE_GROW_DISK"] and
             op.status in ["success", "error", "cancelled"])):
                instance_info = get_instance_info(msg["instance"], self.logger)
                msg["instance_nics"] = instance_info["nics"]
                msg["instance_disks"] = instance_info["disks"]
                msg["instance_hvparams"] = instance_info["hvparams"]

        routekey = "ganeti.%s.event.op" % prefix_from_name(instances)

        return msg, routekey

    def process_network_op(self, op, job_id):
        """ Process OP_NETWORK_* opcodes.

        """

        input = op.input
        op_id = input.OP_ID
        network_name = get_field(input, 'network_name')

        if not network_name:
            return None, None

        self.logger.debug("Job: %d: %s(%s) %s", job_id, op_id,
                          network_name, op.status)

        job_fields = {
            'subnet': get_field(input, 'network'),
            'gateway': get_field(input, 'gateway'),
            "add_reserved_ips": get_field(input, "add_reserved_ips"),
            "remove_reserved_ips": get_field(input, "remove_reserved_ips"),
            # 'network_mode': get_field(input, 'network_mode'),
            # 'network_link': get_field(input, 'network_link'),
            'group_name': get_field(input, 'group_name')}

        msg = {'operation':    op_id,
               'type':         "ganeti-network-status",
               'network':      network_name,
               'job_fields':   job_fields}

        routekey = "ganeti.%s.event.network" % prefix_from_name(network_name)

        return msg, routekey

    def process_cluster_op(self, op, job_id):
        """ Process OP_CLUSTER_* opcodes.

        """

        input = op.input
        op_id = input.OP_ID

        self.logger.debug("Job: %d: %s %s", job_id, op_id, op.status)

        if op_id != "OP_CLUSTER_SET_PARAMS":
            # Send only modifications of cluster
            return None, None

        msg = {'operation':    op_id,
               'type':         "ganeti-cluster-status"}

        routekey = "ganeti.event.cluster"

        return msg, routekey

    def process_tag_op(self, op, job_id):
        """ Process OP_TAGS_* opcodes.

        """
        input = op.input
        op_id = input.OP_ID
        if op_id == "OP_TAGS_SET":
            # NOTE: Check 'dry_run' after 'cluster' because networks and groups
            # do not support the 'dry_run' option.
            if (op.status == "waiting" and input.tags and
               input.kind == "cluster" and input.dry_run):
                # Special where a prefixed cluster tag operation in dry-run
                # mode is used in order to trigger eventd to send a
                # heartbeat message.
                tag = input.tags[0]
                if tag.startswith("snf:eventd:heartbeat"):
                    self.logger.debug("Received heartbeat tag '%s'."
                                      " Sending response.", tag)
                    msg = {"type": "eventd-heartbeat",
                           "cluster": self.cluster_name}
                    return msg, "eventd.heartbeat"

        return None, None
Exemple #7
0
class JobFileHandler(pyinotify.ProcessEvent):
    def __init__(self, logger, cluster_name):
        pyinotify.ProcessEvent.__init__(self)
        self.logger = logger
        self.cluster_name = cluster_name

        # Set max_retries to 0 for unlimited retries.
        self.client = AMQPClient(hosts=settings.AMQP_HOSTS,
                                 confirm_buffer=25,
                                 max_retries=0,
                                 logger=logger)

        handler_logger.info("Attempting to connect to RabbitMQ hosts")

        self.client.connect()
        handler_logger.info("Connected succesfully")

        self.client.exchange_declare(settings.EXCHANGE_GANETI, type='topic')

        self.op_handlers = {
            "INSTANCE": self.process_instance_op,
            "NETWORK": self.process_network_op,
            "CLUSTER": self.process_cluster_op
        }
        # "GROUP": self.process_group_op}

    def process_IN_CLOSE_WRITE(self, event):
        self.process_IN_MOVED_TO(event)

    def process_IN_MOVED_TO(self, event):
        jobfile = os.path.join(event.path, event.name)
        if not event.name.startswith("job-"):
            self.logger.debug("Not a job file: %s" % event.path)
            return

        try:
            data = utils.ReadFile(jobfile)
        except IOError:
            return

        data = serializer.LoadJson(data)
        job = jqueue._QueuedJob.Restore(None, data, False, False)

        job_id = int(job.id)

        for op in job.ops:
            op_id = op.input.OP_ID

            msg = None
            try:
                handler_fn = self.op_handlers[op_id.split('_')[1]]
                msg, routekey = handler_fn(op, job_id)
            except KeyError:
                pass

            if not msg:
                self.logger.debug("Ignoring job: %s: %s", job_id, op_id)
                continue

            # Generate a unique message identifier
            event_time = get_time_from_status(op, job)

            # Get the last line of the op log as message
            try:
                logmsg = op.log[-1][-1]
            except IndexError:
                logmsg = None

            # Add shared attributes for all operations
            msg.update({
                "event_time": event_time,
                "operation": op_id,
                "status": op.status,
                "cluster": self.cluster_name,
                "logmsg": logmsg,
                "result": op.result,
                "jobId": job_id
            })

            if op.status == "success":
                msg["result"] = op.result

            if op_id == "OP_INSTANCE_CREATE" and op.status == "error":
                # In case an instance creation fails send the job input
                # so that the job can be retried if needed.
                msg["job_fields"] = op.Serialize()["input"]

            msg = json.dumps(msg)

            self.logger.debug("Delivering msg: %s (key=%s)", msg, routekey)

            # Send the message to RabbitMQ
            self.client.basic_publish(settings.EXCHANGE_GANETI, routekey, msg)

    def process_instance_op(self, op, job_id):
        """ Process OP_INSTANCE_* opcodes.

        """
        input = op.input
        op_id = input.OP_ID

        instances = None
        instances = get_field(input, 'instance_name')
        if not instances:
            instances = get_field(input, 'instances')
            if not instances or len(instances) > 1:
                # Do not publish messages for jobs with no or multiple
                # instances.  Currently snf-dispatcher can not normally handle
                # these messages
                return None, None
            else:
                instances = instances[0]

        self.logger.debug("Job: %d: %s(%s) %s", job_id, op_id, instances,
                          op.status)

        job_fields = {}
        if op_id in ["OP_INSTANCE_SET_PARAMS", "OP_INSTANCE_CREATE"]:
            job_fields = {
                "nics": get_field(input, "nics"),
                "disks": get_field(input, "disks"),
                "beparams": get_field(input, "beparams")
            }

        msg = {
            "type": "ganeti-op-status",
            "instance": instances,
            "operation": op_id,
            "job_fields": job_fields
        }

        if ((op_id in ["OP_INSTANCE_CREATE", "OP_INSTANCE_STARTUP"]
             and op.status == "success")
                or (op_id == "OP_INSTANCE_SET_PARAMS"
                    and op.status in ["success", "error", "cancelled"])):
            nics = get_instance_nics(msg["instance"], self.logger)
            msg["instance_nics"] = nics

        routekey = "ganeti.%s.event.op" % prefix_from_name(instances)

        return msg, routekey

    def process_network_op(self, op, job_id):
        """ Process OP_NETWORK_* opcodes.

        """

        input = op.input
        op_id = input.OP_ID
        network_name = get_field(input, 'network_name')

        if not network_name:
            return None, None

        self.logger.debug("Job: %d: %s(%s) %s", job_id, op_id, network_name,
                          op.status)

        job_fields = {
            'subnet': get_field(input, 'network'),
            'gateway': get_field(input, 'gateway'),
            "add_reserved_ips": get_field(input, "add_reserved_ips"),
            "remove_reserved_ips": get_field(input, "remove_reserved_ips"),
            # 'network_mode': get_field(input, 'network_mode'),
            # 'network_link': get_field(input, 'network_link'),
            'group_name': get_field(input, 'group_name')
        }

        msg = {
            'operation': op_id,
            'type': "ganeti-network-status",
            'network': network_name,
            'job_fields': job_fields
        }

        routekey = "ganeti.%s.event.network" % prefix_from_name(network_name)

        return msg, routekey

    def process_cluster_op(self, op, job_id):
        """ Process OP_CLUSTER_* opcodes.

        """

        input = op.input
        op_id = input.OP_ID

        self.logger.debug("Job: %d: %s %s", job_id, op_id, op.status)

        if op_id != "OP_CLUSTER_SET_PARAMS":
            # Send only modifications of cluster
            return None, None

        msg = {'operation': op_id, 'type': "ganeti-cluster-status"}

        routekey = "ganeti.event.cluster"

        return msg, routekey
Exemple #8
0
def check_dispatcher_status(pid_file):
    """Check the status of a running snf-dispatcher process.

    Check the status of a running snf-dispatcher process, the PID of which is
    contained in the 'pid_file'. This function will send a 'status-check'
    message to the running snf-dispatcher, wait for dispatcher's response and
    pretty-print the results.

    """
    dispatcher_pid = pidlockfile.read_pid_from_pidfile(pid_file)
    if dispatcher_pid is None:
        sys.stdout.write("snf-dispatcher with PID file '%s' is not running."
                         " PID file does not exist\n" % pid_file)
        sys.exit(1)
    sys.stdout.write("snf-dispatcher (PID: %s): running\n" % dispatcher_pid)

    hostname = get_hostname()
    local_queue = "snf:check_tool:%s:%s" % (hostname, os.getpid())
    dispatcher_queue = queues.get_dispatcher_request_queue(
        hostname, dispatcher_pid)

    log_amqp.setLevel(logging.WARNING)
    try:
        client = AMQPClient(logger=log_amqp)
        client.connect()
        client.queue_declare(queue=local_queue, mirrored=False, exclusive=True)
        client.basic_consume(queue=local_queue,
                             callback=lambda x, y: 0,
                             no_ack=True)
        msg = json.dumps({"action": "status-check", "reply_to": local_queue})
        client.basic_publish("", dispatcher_queue, msg)
    except:
        sys.stdout.write("Error while connecting with AMQP\nError:\n")
        traceback.print_exc()
        sys.exit(1)

    sys.stdout.write("AMQP -> snf-dispatcher: ")
    msg = client.basic_wait(timeout=CHECK_TOOL_ACK_TIMEOUT)
    if msg is None:
        sys.stdout.write("fail\n")
        sys.stdout.write("ERROR: No reply from snf-dipatcher after '%s'"
                         " seconds.\n" % CHECK_TOOL_ACK_TIMEOUT)
        sys.exit(1)
    else:
        try:
            body = json.loads(msg["body"])
            assert (body["action"] == "status-check"), "Invalid action"
            assert (body["status"] == "started"), "Invalid status"
            sys.stdout.write("ok\n")
        except Exception as e:
            sys.stdout.write("Received invalid msg from snf-dispatcher:"
                             " msg: %s error: %s\n" % (msg, e))
            sys.exit(1)

    msg = client.basic_wait(timeout=CHECK_TOOL_REPORT_TIMEOUT)
    if msg is None:
        sys.stdout.write("fail\n")
        sys.stdout.write("ERROR: No status repot after '%s' seconds.\n" %
                         CHECK_TOOL_REPORT_TIMEOUT)
        sys.exit(1)

    sys.stdout.write("Backends:\n")
    status = json.loads(msg["body"])["status"]
    for backend, bstatus in sorted(status.items()):
        sys.stdout.write(" * %s: \n" % backend)
        sys.stdout.write("   snf-dispatcher -> ganeti: %s\n" % bstatus["RAPI"])
        sys.stdout.write("   snf-ganeti-eventd -> AMQP: %s\n" %
                         bstatus["eventd"])
    sys.exit(0)
Exemple #9
0
def main():
    parser = OptionParser()
    parser.add_option('-v', '--verbose', action='store_true', default=False,
                      dest='verbose', help='Enable verbose logging')
    parser.add_option('--host', default=BROKER_HOST, dest='host',
                      help='RabbitMQ host (default: %s)' % BROKER_HOST)
    parser.add_option('--port', default=BROKER_PORT, dest='port',
                      help='RabbitMQ port (default: %s)' % BROKER_PORT, type='int')
    parser.add_option('--user', default=BROKER_USER, dest='user',
                      help='RabbitMQ user (default: %s)' % BROKER_USER)
    parser.add_option('--password', default=BROKER_PASSWORD, dest='password',
                      help='RabbitMQ password (default: %s)' % BROKER_PASSWORD)
    parser.add_option('--vhost', default=BROKER_VHOST, dest='vhost',
                      help='RabbitMQ vhost (default: %s)' % BROKER_VHOST)
    parser.add_option('--queue', default=CONSUMER_QUEUE, dest='queue',
                      help='RabbitMQ queue (default: %s)' % CONSUMER_QUEUE)
    parser.add_option('--exchange', default=CONSUMER_EXCHANGE, dest='exchange',
                      help='RabbitMQ exchange (default: %s)' % CONSUMER_EXCHANGE)
    parser.add_option('--key', default=CONSUMER_KEY, dest='key',
                      help='RabbitMQ key (default: %s)' % CONSUMER_KEY)
    parser.add_option('--callback', default=None, dest='callback',
                      help='Callback function to consume messages')
    parser.add_option('--test', action='store_true', default=False,
                      dest='test', help='Produce a dummy message for testing')
    opts, args = parser.parse_args()

    DEBUG = False
    if opts.verbose:
        DEBUG = True
    logging.basicConfig(
        format='%(asctime)s [%(levelname)s] %(name)s %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S',
        level=logging.DEBUG if DEBUG else logging.INFO)
    logger = logging.getLogger('dispatcher')

    host =  'amqp://%s:%s@%s:%s' % (opts.user, opts.password, opts.host, opts.port)
    queue = opts.queue
    key = opts.key
    exchange = opts.exchange
    
    client = AMQPClient(hosts=[host])
    client.connect()

    if opts.test:
        client.exchange_declare(exchange=exchange,
                                type='topic')
        client.basic_publish(exchange=exchange,
                             routing_key=key,
                             body= json.dumps({"test": "0123456789"}))
        client.close()
        sys.exit()

    callback = None
    if opts.callback:
        cb = opts.callback.rsplit('.', 1)
        if len(cb) == 2:
            __import__(cb[0])
            cb_module = sys.modules[cb[0]]
            callback = getattr(cb_module, cb[1])

    def handle_message(client, msg):
        logger.debug('%s', msg)
        if callback:
            callback(msg)
        client.basic_ack(msg)

    client.queue_declare(queue=queue)
    client.queue_bind(queue=queue,
                      exchange=exchange,
                      routing_key=key)

    client.basic_consume(queue=queue, callback=handle_message)

    try:
        while True:
            client.basic_wait()
    except KeyboardInterrupt:
        pass
    finally:
        client.close()
Exemple #10
0
def main():
    parser = OptionParser()
    parser.add_option('-v',
                      '--verbose',
                      action='store_true',
                      default=False,
                      dest='verbose',
                      help='Enable verbose logging')
    parser.add_option('--host',
                      default=BROKER_HOST,
                      dest='host',
                      help='RabbitMQ host (default: %s)' % BROKER_HOST)
    parser.add_option('--port',
                      default=BROKER_PORT,
                      dest='port',
                      help='RabbitMQ port (default: %s)' % BROKER_PORT,
                      type='int')
    parser.add_option('--user',
                      default=BROKER_USER,
                      dest='user',
                      help='RabbitMQ user (default: %s)' % BROKER_USER)
    parser.add_option('--password',
                      default=BROKER_PASSWORD,
                      dest='password',
                      help='RabbitMQ password (default: %s)' % BROKER_PASSWORD)
    parser.add_option('--vhost',
                      default=BROKER_VHOST,
                      dest='vhost',
                      help='RabbitMQ vhost (default: %s)' % BROKER_VHOST)
    parser.add_option('--queue',
                      default=CONSUMER_QUEUE,
                      dest='queue',
                      help='RabbitMQ queue (default: %s)' % CONSUMER_QUEUE)
    parser.add_option('--exchange',
                      default=CONSUMER_EXCHANGE,
                      dest='exchange',
                      help='RabbitMQ exchange (default: %s)' %
                      CONSUMER_EXCHANGE)
    parser.add_option('--key',
                      default=CONSUMER_KEY,
                      dest='key',
                      help='RabbitMQ key (default: %s)' % CONSUMER_KEY)
    parser.add_option('--callback',
                      default=None,
                      dest='callback',
                      help='Callback function to consume messages')
    parser.add_option('--test',
                      action='store_true',
                      default=False,
                      dest='test',
                      help='Produce a dummy message for testing')
    opts, args = parser.parse_args()

    DEBUG = False
    if opts.verbose:
        DEBUG = True
    logging.basicConfig(
        format='%(asctime)s [%(levelname)s] %(name)s %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S',
        level=logging.DEBUG if DEBUG else logging.INFO)
    logger = logging.getLogger('dispatcher')

    host = 'amqp://%s:%s@%s:%s' % (opts.user, opts.password, opts.host,
                                   opts.port)
    queue = opts.queue
    key = opts.key
    exchange = opts.exchange

    client = AMQPClient(hosts=[host])
    client.connect()

    if opts.test:
        client.exchange_declare(exchange=exchange, type='topic')
        client.basic_publish(exchange=exchange,
                             routing_key=key,
                             body=json.dumps({"test": "0123456789"}))
        client.close()
        sys.exit()

    callback = None
    if opts.callback:
        cb = opts.callback.rsplit('.', 1)
        if len(cb) == 2:
            __import__(cb[0])
            cb_module = sys.modules[cb[0]]
            callback = getattr(cb_module, cb[1])

    def handle_message(client, msg):
        logger.debug('%s', msg)
        if callback:
            callback(msg)
        client.basic_ack(msg)

    client.queue_declare(queue=queue)
    client.queue_bind(queue=queue, exchange=exchange, routing_key=key)

    client.basic_consume(queue=queue, callback=handle_message)

    try:
        while True:
            client.basic_wait()
    except KeyboardInterrupt:
        pass
    finally:
        client.close()
def check_dispatcher_status(pid_file):
    """Check the status of a running snf-dispatcher process.

    Check the status of a running snf-dispatcher process, the PID of which is
    contained in the 'pid_file'. This function will send a 'status-check'
    message to the running snf-dispatcher, wait for dispatcher's response and
    pretty-print the results.

    """
    dispatcher_pid = pidlockfile.read_pid_from_pidfile(pid_file)
    if dispatcher_pid is None:
        sys.stdout.write("snf-dispatcher with PID file '%s' is not running."
                         " PID file does not exist\n" % pid_file)
        sys.exit(1)
    sys.stdout.write("snf-dispatcher (PID: %s): running\n" % dispatcher_pid)

    hostname = get_hostname()
    local_queue = "snf:check_tool:%s:%s" % (hostname, os.getpid())
    dispatcher_queue = queues.get_dispatcher_request_queue(hostname,
                                                           dispatcher_pid)

    log_amqp.setLevel(logging.WARNING)
    try:
        client = AMQPClient(logger=log_amqp)
        client.connect()
        client.queue_declare(queue=local_queue, mirrored=False, exclusive=True)
        client.basic_consume(queue=local_queue, callback=lambda x, y: 0,
                             no_ack=True)
        msg = json.dumps({"action": "status-check", "reply_to": local_queue})
        client.basic_publish("", dispatcher_queue, msg)
    except:
        sys.stdout.write("Error while connecting with AMQP\nError:\n")
        traceback.print_exc()
        sys.exit(1)

    sys.stdout.write("AMQP -> snf-dispatcher: ")
    msg = client.basic_wait(timeout=CHECK_TOOL_ACK_TIMEOUT)
    if msg is None:
        sys.stdout.write("fail\n")
        sys.stdout.write("ERROR: No reply from snf-dipatcher after '%s'"
                         " seconds.\n" % CHECK_TOOL_ACK_TIMEOUT)
        sys.exit(1)
    else:
        try:
            body = json.loads(msg["body"])
            assert(body["action"] == "status-check"), "Invalid action"
            assert(body["status"] == "started"), "Invalid status"
            sys.stdout.write("ok\n")
        except Exception as e:
            sys.stdout.write("Received invalid msg from snf-dispatcher:"
                             " msg: %s error: %s\n" % (msg, e))
            sys.exit(1)

    msg = client.basic_wait(timeout=CHECK_TOOL_REPORT_TIMEOUT)
    if msg is None:
        sys.stdout.write("fail\n")
        sys.stdout.write("ERROR: No status repot after '%s' seconds.\n"
                         % CHECK_TOOL_REPORT_TIMEOUT)
        sys.exit(1)

    sys.stdout.write("Backends:\n")
    status = json.loads(msg["body"])["status"]
    for backend, bstatus in sorted(status.items()):
        sys.stdout.write(" * %s: \n" % backend)
        sys.stdout.write("   snf-dispatcher -> ganeti: %s\n" %
                         bstatus["RAPI"])
        sys.stdout.write("   snf-ganeti-eventd -> AMQP: %s\n" %
                         bstatus["eventd"])
    sys.exit(0)