Пример #1
0
    def add_endpoint(self, event):
        endpoint_data = event.metadata
        service_name = endpoint_data['metadata']['name']
        namespace = endpoint_data['metadata']['namespace']
        ips = endpoint_data.get('custom', {}).get('ips', [])

        vlog.dbg("received endpoint data %s" % (endpoint_data))

        cache_key = "%s_%s" % (namespace, service_name)
        cached_service = self.service_cache.get(cache_key, {})
        if cached_service:
            service_data = cached_service
        else:
            try:
                response_json = kubernetes.get_service(
                                                   variables.K8S_API_SERVER,
                                                   namespace, service_name)
            except exceptions.NotFound:
                vlog.dbg("No service found for endpoint %s " % service_name)
                return
            except Exception as e:
                vlog.err("add_endpoint: k8s get service (%s)" % (str(e)))
                return

            service_data = response_json

        service_type = service_data['spec'].get('type')
        if service_type != "ClusterIP" and service_type != "NodePort":
            return

        self._update_vip(service_data, ips)
Пример #2
0
    def _process_service_event(self, event):
        service_data = event["object"]
        vlog.dbg("obtained service data is %s" % json.dumps(service_data))

        cluster_ip = service_data["spec"].get("clusterIP")

        # When service is created, we may get an event where there is no
        # cluster_ip (VIP) allocated to it.
        if not cluster_ip:
            return

        service_name = service_data["metadata"]["name"]
        namespace = service_data["metadata"]["namespace"]
        event_type = event["type"]

        cache_key = "%s_%s" % (namespace, service_name)
        cached_service = self.service_cache.get(cache_key, {})
        self._update_service_cache(event_type, cache_key, service_data)

        # TODO: A service can be patched (i.e modified) and its ports
        # and external_ips can be changed.  We need a way to handle it.
        # One way would be to send a delete and create connectivity events.

        has_conn_event = False
        if not cached_service:
            has_conn_event = True
        elif event_type == "DELETED":
            has_conn_event = True
        else:
            return

        if has_conn_event:
            vlog.dbg("Sending connectivity event for event %s on service %s" % (event_type, service_name))
            self._send_connectivity_event(event_type, service_name, service_data)
Пример #3
0
 def _process_pod_event(self, event):
     if event.event_type == "DELETED":
         vlog.dbg("Received a pod delete event %s" % (event.metadata))
         self.mode.delete_logical_port(event)
     else:
         vlog.dbg("Received a pod ADD/MODIFY event %s" % (event.metadata))
         self.mode.create_logical_port(event)
Пример #4
0
    def accept(self):
        """Tries to accept a new connection on this passive stream.  Returns
        (error, stream): if successful, 'error' is 0 and 'stream' is the new
        Stream object, and on failure 'error' is a positive errno value and
        'stream' is None.

        Will not block waiting for a connection.  If no connection is ready to
        be accepted, returns (errno.EAGAIN, None) immediately."""
        if sys.platform == 'win32' and self.socket is None:
            return self.__accept_windows()
        while True:
            try:
                sock, addr = self.socket.accept()
                ovs.socket_util.set_nonblocking(sock)
                if (sys.platform != 'win32' and sock.family == socket.AF_UNIX):
                    return 0, Stream(sock, "unix:%s" % addr, 0)
                return 0, Stream(sock, 'ptcp:%s:%s' % (addr[0],
                                                       str(addr[1])), 0)
            except socket.error as e:
                error = ovs.socket_util.get_exception_errno(e)
                if sys.platform == 'win32' and error == errno.WSAEWOULDBLOCK:
                    # WSAEWOULDBLOCK would be the equivalent on Windows
                    # for EAGAIN on Unix.
                    error = errno.EAGAIN
                if error != errno.EAGAIN:
                    # XXX rate-limit
                    vlog.dbg("accept: %s" % os.strerror(error))
                return error, None
Пример #5
0
    def _process_pod_event(self, event):
        vlog.dbg("obtained pod event %s" % json.dumps(event))
        pod_data = event['object']
        event_type = event['type']

        pod_name = pod_data['metadata'].get('name')
        namespace = pod_data['metadata'].get('namespace')
        if not pod_name or not namespace:
            return

        # To create a logical port for a pod, we need to know the node
        # where it has been scheduled.  The first event from the API server
        # may not have this information, but we will eventually get it.
        if event_type != 'DELETED' and not pod_data['spec'].get('nodeName'):
            return

        cache_key = "%s_%s" % (namespace, pod_name)
        cached_pod = self.pod_cache.get(cache_key, {})
        self._update_pod_cache(event_type, cache_key, pod_data)

        has_conn_event = False
        if not cached_pod:
            has_conn_event = True
        elif event_type == 'DELETED':
            has_conn_event = True
        else:
            return

        if has_conn_event:
            vlog.dbg("Sending connectivity event for event %s on pod %s"
                     % (event_type, pod_name))
            self._send_connectivity_event(event_type, pod_name, pod_data)
Пример #6
0
 def _process_service_event(self, event):
     if event.event_type == "DELETED":
         vlog.dbg("Received a service delete event %s" % (event.metadata))
     else:
         vlog.dbg("Received a service ADD/MODIFY event %s"
                  % (event.metadata))
     self.mode.update_vip(event)
Пример #7
0
 def __call__(self, request):
     handler = self.get_handler(request)
     if handler:
         vlog.dbg("Handling request '%s %s' with %s"
                  % (request.method, request.path, str(handler)))
         return handler.handle_request(request)
     else:
         return NOT_SUPPORTED_RESPONSE
Пример #8
0
    def _create_load_balancer_vip(self, namespace, load_balancer, service_ip,
                                  ips, port, target_port, protocol):
        # With service_ip:port as a VIP, create an entry in 'load_balancer'

        vlog.dbg("received event to create/modify load_balancer (%s) vip "
                 "service_ip=%s, ips=%s, port=%s, target_port=%s, protocol=%s"
                 % (load_balancer, service_ip, ips, port, target_port,
                    protocol))
        if not port or not target_port or not protocol or not load_balancer:
            return

        # key is of the form "IP:port" (with quotes around)
        key = "\"" + service_ip + ":" + str(port) + "\""
        if not ips:
            try:
                ovn_nbctl("remove", "load_balancer", load_balancer,
                          "vips", key)
            except Exception as e:
                vlog.err("_create_load_balancer_vip remove: (%s)" % (str(e)))
            return

        if target_port.isdigit():
            # target is of the form "IP1:port, IP2:port, IP3:port"
            target_endpoints = ",".join(["%s:%s" % (ip, target_port)
                                         for ip in ips])
        else:
            # 'target_port' is a string.  We should get its number
            # from the cache.
            if not self.port_name_cache.get(namespace):
                vlog.warn("targetPort of %s in ns %s does not have an "
                          "associated port. Ignoring endpoint creation."
                          % (target_port, namespace))
                return
            target_endpoint_list = []
            for ip in ips:
                if not self.port_name_cache[namespace].get(ip):
                    continue

                num_port = self.port_name_cache[namespace][ip].get(target_port)
                if not num_port:
                    continue

                target_endpoint_list.append("%s:%s" % (ip, num_port))

            if not target_endpoint_list:
                vlog.warn("targetPort of %s in ns %s does not have any "
                          "associated ports. Ignoring endpoint creation."
                          % (target_port, namespace))
                return
            target_endpoints = ",".join(target_endpoint_list)

        target = "\"" + target_endpoints + "\""

        try:
            ovn_nbctl("set", "load_balancer", load_balancer,
                      "vips:" + key + "=" + target)
        except Exception as e:
            vlog.err("_create_load_balancer_vip add: (%s)" % (str(e)))
Пример #9
0
    def _transition(self, now, state):
        if self.state == Reconnect.ConnectInProgress:
            self.n_attempted_connections += 1
            if state == Reconnect.Active:
                self.n_successful_connections += 1

        connected_before = self.state.is_connected
        connected_now = state.is_connected
        if connected_before != connected_now:
            if connected_before:
                self.total_connected_duration += now - self.last_connected
            self.seqno += 1

        vlog.dbg("%s: entering %s" % (self.name, state.name))
        self.state = state
        self.state_entered = now
Пример #10
0
 def run(self):
     events = []
     while True:
         try:
             # TODO: Not sure how wait with timeout plays with eventlet
             event = self.event_queue.get_nowait()
             events.append(event)
             vlog.dbg("Received event %s from %s"
                      % (event.event_type, event.source))
         except queue.Empty:
             # no element in the queue
             if events:
                 self.process_events(events)
                 events = []
             else:
                 # TODO: Do something better here.
                 time.sleep(0.1)
Пример #11
0
 def __log_wakeup(self, events):
     if not events:
         vlog.dbg("%d-ms timeout" % self.timeout)
     else:
         for fd, revents in events:
             if revents != 0:
                 s = ""
                 if revents & POLLIN:
                     s += "[POLLIN]"
                 if revents & POLLOUT:
                     s += "[POLLOUT]"
                 if revents & POLLERR:
                     s += "[POLLERR]"
                 if revents & POLLHUP:
                     s += "[POLLHUP]"
                 if revents & POLLNVAL:
                     s += "[POLLNVAL]"
                 vlog.dbg("%s on fd %d" % (s, fd))
Пример #12
0
    def _create_load_balancer_vip(self, service_type, service_ip, ips, port,
                                  target_port, protocol):
        vlog.dbg("received event to create/modify load_balancer vip with "
                 "service_type=%s, service_ip=%s, ips=%s, port=%s,"
                 "target_port=%s, protocol=%s"
                 % (service_type, service_ip, ips, port, target_port,
                    protocol))
        if not port or not target_port or not protocol or not service_type:
            return

        load_balancer = ""
        if protocol == "TCP" and service_type == "ClusterIP":
            load_balancer = variables.K8S_CLUSTER_LB_TCP
        elif protocol == "UDP" and service_type == "ClusterIP":
            load_balancer = variables.K8S_CLUSTER_LB_UDP
        elif protocol == "TCP" and service_type == "NodePort":
            load_balancer = variables.K8S_NS_LB_TCP
        elif protocol == "UDP" and service_type == "NodePort":
            load_balancer = variables.K8S_NS_LB_UDP

        if not load_balancer:
            return

        # key is of the form "IP:port" (with quotes around)
        key = "\"" + service_ip + ":" + str(port) + "\""
        if not ips:
            try:
                ovn_nbctl("remove", "load_balancer", load_balancer,
                          "vips", key)
            except Exception as e:
                vlog.err("_create_load_balancer_vip remove: (%s)" % (str(e)))
            return

        # target is of the form "IP1:port, IP2:port, IP3:port"
        target_endpoints = ",".join(["%s:%s" % (ip, target_port)
                                     for ip in ips])
        target = "\"" + target_endpoints + "\""

        try:
            ovn_nbctl("set", "load_balancer", load_balancer,
                      "vips:" + key + "=" + target)
        except Exception as e:
            vlog.err("_create_load_balancer_vip add: (%s)" % (str(e)))
Пример #13
0
Файл: stream.py Проект: albd/ovs
    def accept(self):
        """Tries to accept a new connection on this passive stream.  Returns
        (error, stream): if successful, 'error' is 0 and 'stream' is the new
        Stream object, and on failure 'error' is a positive errno value and
        'stream' is None.

        Will not block waiting for a connection.  If no connection is ready to
        be accepted, returns (errno.EAGAIN, None) immediately."""

        while True:
            try:
                sock, addr = self.socket.accept()
                ovs.socket_util.set_nonblocking(sock)
                return 0, Stream(sock, "unix:%s" % addr, 0)
            except socket.error as e:
                error = ovs.socket_util.get_exception_errno(e)
                if error != errno.EAGAIN:
                    # XXX rate-limit
                    vlog.dbg("accept: %s" % os.strerror(error))
                return error, None
Пример #14
0
def get_pod_annotations(server, namespace, pod):
    ca_certificate, api_token = _get_api_params()
    url = ("%s/api/v1/namespaces/%s/pods/%s" %
           (server, namespace, pod))

    headers = {}
    if api_token:
        headers['Authorization'] = 'Bearer %s' % api_token

    if ca_certificate:
        response = requests.get(url, headers=headers, verify=ca_certificate)
    else:
        response = requests.get(url, headers=headers)
    if not response:
        # TODO: raise here
        return
    json_response = response.json()
    annotations = json_response['metadata'].get('annotations')
    vlog.dbg("Annotations for pod %s: %s" % (pod, annotations))
    return annotations
Пример #15
0
    def update_vip(self, event):
        service_data = event.metadata
        service_type = service_data['spec'].get('type')
        vlog.dbg("update_vip: received service data %s" % (service_data))

        # We only care about services that are of type 'clusterIP' and
        # 'nodePort'.
        if service_type != "ClusterIP" and service_type != "NodePort":
            return

        service_name = service_data['metadata']['name']
        event_type = event.event_type
        namespace = service_data['metadata']['namespace']

        cache_key = "%s_%s" % (namespace, service_name)

        self._update_service_cache(event_type, cache_key, service_data)

        if event.event_type == "DELETED":
            vlog.dbg("received service delete event.")
            self._update_vip(service_data, None)
Пример #16
0
    def _process_endpoint_event(self, event):
        vlog.dbg("obtained endpoint event %s" % json.dumps(event))
        endpoint_data = event['object']
        event_type = event['type']
        endpoint_id = endpoint_data['metadata']['uid']
        endpoint_name = endpoint_data['metadata'].get('name')
        namespace = endpoint_data['metadata'].get('namespace')

        ips = set()
        subsets = endpoint_data.get('subsets')
        if subsets:
            for subset in subsets:
                addresses = subset.get('addresses')
                if not addresses:
                    continue
                for address in addresses:
                    ip = address.get('ip')
                    if ip:
                        ips.add(ip)

        if not endpoint_name or not namespace:
            return

        cached_endpoint = self.endpoint_cache.get(endpoint_id)
        if (not cached_endpoint or
                cached_endpoint.get('custom', {}).get('ips') != ips):
            vlog.dbg("Sending connectivity event for event %s on endpoint %s"
                     % (event_type, endpoint_name))
            if cached_endpoint:
                custom_data = cached_endpoint.setdefault('custom', {})
            else:
                custom_data = {}
            custom_data['ips'] = ips
            endpoint_data['custom'] = custom_data
            self._send_connectivity_event(event_type,
                                          endpoint_name,
                                          endpoint_data)
            # Update cache
            self.endpoint_cache[endpoint_id] = endpoint_data
Пример #17
0
def set_pod_annotation(server, namespace, pod, key, value):
    ca_certificate, api_token = _get_api_params()
    url = ("%s/api/v1/namespaces/%s/pods/%s" %
           (server, namespace, pod))

    # NOTE: This is not probably compliant with RFC 7386 but appears to work
    # with the kubernetes API server.
    patch = {
        'metadata': {
            'annotations': {
                key: value
            }
        }
    }

    headers = {'Content-Type': 'application/merge-patch+json'}
    if api_token:
        headers['Authorization'] = 'Bearer %s' % api_token
    if ca_certificate:
        response = requests.patch(
            url,
            data=json.dumps(patch),
            headers=headers,
            verify=ca_certificate)
    else:
        response = requests.patch(
            url,
            data=json.dumps(patch),
            headers=headers)

    if not response:
        # TODO: Raise appropriate exception
        raise Exception("Something went wrong while annotating pod: %s" %
                        response.text)
    json_response = response.json()
    annotations = json_response['metadata'].get('annotations')
    vlog.dbg("Annotations for pod after update %s: %s" % (pod, annotations))
    return annotations
Пример #18
0
 def __log_msg(self, title, msg):
     if vlog.dbg_is_enabled():
         vlog.dbg("%s: %s %s" % (self.name, title, msg))
Пример #19
0
def __read_pidfile(pidfile, delete_if_stale):
    if _pidfile_dev is not None:
        try:
            s = os.stat(pidfile)
            if s.st_ino == _pidfile_ino and s.st_dev == _pidfile_dev:
                # It's our own pidfile.  We can't afford to open it,
                # because closing *any* fd for a file that a process
                # has locked also releases all the locks on that file.
                #
                # Fortunately, we know the associated pid anyhow.
                return os.getpid()
        except OSError:
            pass

    try:
        file_handle = open(pidfile, "r+")
    except IOError as e:
        if e.errno == errno.ENOENT and delete_if_stale:
            return 0
        vlog.warn("%s: open: %s" % (pidfile, e.strerror))
        return -e.errno

    # Python fcntl doesn't directly support F_GETLK so we have to just try
    # to lock it.
    try:
        fcntl.lockf(file_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)

        # pidfile exists but wasn't locked by anyone.  Now we have the lock.
        if not delete_if_stale:
            file_handle.close()
            vlog.warn("%s: pid file is stale" % pidfile)
            return -errno.ESRCH

        # Is the file we have locked still named 'pidfile'?
        try:
            raced = False
            s = os.stat(pidfile)
            s2 = os.fstat(file_handle.fileno())
            if s.st_ino != s2.st_ino or s.st_dev != s2.st_dev:
                raced = True
        except IOError:
            raced = True
        if raced:
            vlog.warn("%s: lost race to delete pidfile" % pidfile)
            return -errno.EALREADY

        # We won the right to delete the stale pidfile.
        try:
            os.unlink(pidfile)
        except IOError as e:
            vlog.warn("%s: failed to delete stale pidfile (%s)" %
                      (pidfile, e.strerror))
            return -e.errno
        else:
            vlog.dbg("%s: deleted stale pidfile" % pidfile)
            file_handle.close()
            return 0
    except IOError as e:
        if e.errno not in [errno.EACCES, errno.EAGAIN]:
            vlog.warn("%s: fcntl: %s" % (pidfile, e.strerror))
            return -e.errno

    # Someone else has the pidfile locked.
    try:
        try:
            error = int(file_handle.readline())
        except IOError as e:
            vlog.warn("%s: read: %s" % (pidfile, e.strerror))
            error = -e.errno
        except ValueError:
            vlog.warn("%s does not contain a pid" % pidfile)
            error = -errno.EINVAL

        return error
    finally:
        try:
            file_handle.close()
        except IOError:
            pass
Пример #20
0
                raced = True
        except IOError:
            raced = True
        if raced:
            vlog.warn("%s: lost race to delete pidfile" % pidfile)
            return -errno.EALREADY

        # We won the right to delete the stale pidfile.
        try:
            os.unlink(pidfile)
        except IOError, e:
            vlog.warn("%s: failed to delete stale pidfile (%s)"
                            % (pidfile, e.strerror))
            return -e.errno
        else:
            vlog.dbg("%s: deleted stale pidfile" % pidfile)
            file_handle.close()
            return 0
    except IOError, e:
        if e.errno not in [errno.EACCES, errno.EAGAIN]:
            vlog.warn("%s: fcntl: %s" % (pidfile, e.strerror))
            return -e.errno

    # Someone else has the pidfile locked.
    try:
        try:
            error = int(file_handle.readline())
        except IOError, e:
            vlog.warn("%s: read: %s" % (pidfile, e.strerror))
            error = -e.errno
        except ValueError:
Пример #21
0
 def __log_msg(self, title, msg):
     vlog.dbg("%s: %s %s" % (self.name, title, msg))
Пример #22
0
 def __log_msg(self, title, msg):
     vlog.dbg("%s: %s %s" % (self.name, title, msg))
Пример #23
0
                raced = True
        except IOError:
            raced = True
        if raced:
            vlog.warn("%s: lost race to delete pidfile" % pidfile)
            return -errno.EALREADY

        # We won the right to delete the stale pidfile.
        try:
            os.unlink(pidfile)
        except IOError, e:
            vlog.warn("%s: failed to delete stale pidfile (%s)"
                            % (pidfile, e.strerror))
            return -e.errno
        else:
            vlog.dbg("%s: deleted stale pidfile" % pidfile)
            file_handle.close()
            return 0
    except IOError, e:
        if e.errno not in [errno.EACCES, errno.EAGAIN]:
            vlog.warn("%s: fcntl: %s" % (pidfile, e.strerror))
            return -e.errno

    # Someone else has the pidfile locked.
    try:
        try:
            error = int(file_handle.readline())
        except IOError, e:
            vlog.warn("%s: read: %s" % (pidfile, e.strerror))
            error = -e.errno
        except ValueError:
Пример #24
0
def write(data, extschema, idl, txn=None, block=False):
    """Write a new configuration to OpenSwitch OVSDB database

    Args:
        data (dict): The new configuration represented as a Python
            dictionary object.
        extschema (opslib.RestSchema): This is the
            parsed extended-schema (vswitch.extschema) object.
        idl (ovs.db.idl.Idl): This is the IDL object that
            represents the OVSDB IDL.
        txn (ovs.db.idl.Transaction): OVSDB transaction object.
        block (boolean): if block is True, commit_block() is used

    Returns:
        result : The result of transaction commit
    """
    if txn is None:
        try:
            txn = Transaction(idl)
            block = True
        except AssertionError as e:
            vlog.dbg('error in creating transaction: %s' % e)
            return e

    # dc.read returns config db with 'System' table
    # indexed to 'System' keyword. Replace it with
    # current database's System row UUID so that all
    # tables in 'data' are represented the same way

    try:
        system_uuid = idl.tables[
            ops.constants.OVSDB_SCHEMA_SYSTEM_TABLE].rows.keys()[0]
        data[ops.constants.OVSDB_SCHEMA_SYSTEM_TABLE] = {
            system_uuid: data[ops.constants.OVSDB_SCHEMA_SYSTEM_TABLE]
        }

        _write.setup_validators(extschema, idl)

        # iterate over all top-level tables i.e. root
        for table_name, tableschema in extschema.ovs_tables.iteritems():

            # iterate over non-children tables
            if extschema.ovs_tables[table_name].parent is not None:
                continue

            # set up the non-child table
            _write.setup_table(table_name, data, extschema, idl, txn)

        # iterate over all tables to fill in references
        for table_name, tableschema in extschema.ovs_tables.iteritems():

            if extschema.ovs_tables[table_name].parent is not None:
                continue

            _write.setup_references(table_name, data, extschema, idl)

        validation_errors = _write.exec_validators()
        if validation_errors:
            return (txn.ERROR, validation_errors)

    except Exception as e:
        txn.abort()
        return (txn.ERROR, e)

    try:
        if not block:
            # txn maybe be incomplete
            result = txn.commit()
        else:
            # txn will block until it is completed
            result = txn.commit_block()
        vlog.dbg('transacton result: %s' % result)
        return (result, txn.get_error())

    except Exception as e:
        vlog.err('transaction exception: %s' % e)
        txn.abort()
        return (txn.ERROR, e)
Пример #25
0
 def run(fsm, now):
     vlog.dbg("%s: idle %d ms, sending inactivity probe"
              % (fsm.name,
                 now - max(fsm.last_activity, fsm.state_entered)))
     fsm._transition(now, Reconnect.Idle)
     return PROBE
Пример #26
0
 def __log_msg(self, title, msg):
     if vlog.dbg_is_enabled():
         vlog.dbg("%s: %s %s" % (self.name, title, msg))
Пример #27
0
 def run(fsm, now):
     vlog.dbg("%s: idle %d ms, sending inactivity probe"
              % (fsm.name,
                 now - max(fsm.last_received, fsm.state_entered)))
     fsm._transition(now, Reconnect.Idle)
     return PROBE
                  and msg.method == "stolen"):
                # Someone else stole our lock.
                self.__parse_lock_notify(msg.params, False)
            elif msg.type == ovs.jsonrpc.Message.T_NOTIFY and msg.id == "echo":
                # Reply to our echo request.  Ignore it.
                pass
            elif (msg.type in (ovs.jsonrpc.Message.T_ERROR,
                               ovs.jsonrpc.Message.T_REPLY)
                  and self.__txn_process_reply(msg)):
                # __txn_process_reply() did everything needed.
                pass
            else:
                # This can happen if a transaction is destroyed before we
                # receive the reply, so keep the log level low.
                vlog.dbg("%s: received unexpected %s message"
                         % (self._session.get_name(),
                             ovs.jsonrpc.Message.type_to_string(msg.type)))

        return initial_change_seqno != self.change_seqno

    def wait(self, poller):
        """Arranges for poller.block() to wake up when self.run() has something
        to do or when activity occurs on a transaction on 'self'."""
        self._session.wait(poller)
        self._session.recv_wait(poller)

    def has_ever_connected(self):
        """Returns True, if the IDL successfully connected to the remote
        database and retrieved its contents (even if the connection
        subsequently dropped and is in the process of reconnecting).  If so,
        then the IDL contains an atomic snapshot of the database's contents
Пример #29
0
def __read_pidfile(pidfile, delete_if_stale):
    if _pidfile_dev is not None:
        try:
            s = os.stat(pidfile)
            if s.st_ino == _pidfile_ino and s.st_dev == _pidfile_dev:
                # It's our own pidfile.  We can't afford to open it,
                # because closing *any* fd for a file that a process
                # has locked also releases all the locks on that file.
                #
                # Fortunately, we know the associated pid anyhow.
                return os.getpid()
        except OSError:
            pass

    try:
        file_handle = open(pidfile, "r+")
    except IOError as e:
        if e.errno == errno.ENOENT and delete_if_stale:
            return 0
        vlog.warn("%s: open: %s" % (pidfile, e.strerror))
        return -e.errno

    # Python fcntl doesn't directly support F_GETLK so we have to just try
    # to lock it.
    try:
        fcntl.lockf(file_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)

        # pidfile exists but wasn't locked by anyone.  Now we have the lock.
        if not delete_if_stale:
            file_handle.close()
            vlog.warn("%s: pid file is stale" % pidfile)
            return -errno.ESRCH

        # Is the file we have locked still named 'pidfile'?
        try:
            raced = False
            s = os.stat(pidfile)
            s2 = os.fstat(file_handle.fileno())
            if s.st_ino != s2.st_ino or s.st_dev != s2.st_dev:
                raced = True
        except IOError:
            raced = True
        if raced:
            vlog.warn("%s: lost race to delete pidfile" % pidfile)
            return -errno.EALREADY

        # We won the right to delete the stale pidfile.
        try:
            os.unlink(pidfile)
        except IOError as e:
            vlog.warn("%s: failed to delete stale pidfile (%s)"
                            % (pidfile, e.strerror))
            return -e.errno
        else:
            vlog.dbg("%s: deleted stale pidfile" % pidfile)
            file_handle.close()
            return 0
    except IOError as e:
        if e.errno not in [errno.EACCES, errno.EAGAIN]:
            vlog.warn("%s: fcntl: %s" % (pidfile, e.strerror))
            return -e.errno

    # Someone else has the pidfile locked.
    try:
        try:
            error = int(file_handle.readline())
        except IOError as e:
            vlog.warn("%s: read: %s" % (pidfile, e.strerror))
            error = -e.errno
        except ValueError:
            vlog.warn("%s does not contain a pid" % pidfile)
            error = -errno.EINVAL

        return error
    finally:
        try:
            file_handle.close()
        except IOError:
            pass
Пример #30
0
 def _process_endpoint_event(self, event):
     if event.event_type != "DELETED":
         vlog.dbg("Received a endpoint ADD/MODIFY event %s"
                  % (event.metadata))
         self.mode.add_endpoint(event)