Ejemplo n.º 1
0
def test_auto_addr_list_warnings():
    try:
        orig = dict(os.environ)
        os.environ.pop('EPICS_CA_AUTO_ADDR_LIST', None)
        os.environ.pop('EPICS_CA_ADDR_LIST', None)
        os.environ.pop('EPICS_CAS_AUTO_BEACON_ADDR_LIST', None)
        os.environ.pop('EPICS_CAS_BEACON_ADDR_LIST', None)

        with pytest.warns(None) as record:
            ca.get_environment_variables()  # no warning
            assert not record
        os.environ['EPICS_CA_ADDR_LIST'] = '127.0.0.1'
        with pytest.warns(UserWarning):
            ca.get_environment_variables()
        os.environ['EPICS_CA_AUTO_ADDR_LIST'] = 'no'
        with pytest.warns(None) as record:
            ca.get_environment_variables()  # no warning
            assert not record
        os.environ['EPICS_CAS_BEACON_ADDR_LIST'] = '127.0.0.1'
        with pytest.warns(UserWarning):
            ca.get_environment_variables()
        os.environ['EPICS_CAS_AUTO_BEACON_ADDR_LIST'] = 'no'
        with pytest.warns(None) as record:
            ca.get_environment_variables()  # no warning
            assert not record

    finally:
        # Restore env as it was.
        os.environ.pop('EPICS_CA_AUTO_ADDR_LIST', None)
        os.environ.pop('EPICS_CA_ADDR_LIST', None)
        os.environ.pop('EPICS_CAS_AUTO_BEACON_ADDR_LIST', None)
        os.environ.pop('EPICS_CAS_BEACON_ADDR_LIST', None)
        os.environ.update(orig)
Ejemplo n.º 2
0
def test_env_util_smoke(protocol):
    ca.get_environment_variables()
    try:
        ca.get_netifaces_addresses()
    except RuntimeError:
        # Netifaces may be unavailable
        ...

    ca.get_address_list(protocol=protocol)
    ca.get_beacon_address_list(protocol=protocol)
    ca._utils.get_manually_specified_beacon_addresses(protocol=protocol)
    ca._utils.get_manually_specified_client_addresses(protocol=protocol)
    ca.get_server_address_list(protocol=protocol)
Ejemplo n.º 3
0
def spawn_repeater():
    """
    Spawn a repeater process unless one is not already running.
    """
    host = '0.0.0.0'  # not configurable for a spawned repeater
    port = caproto.get_environment_variables()['EPICS_CA_REPEATER_PORT']
    try:
        sock = check_for_running_repeater((host, port))
    except RepeaterAlreadyRunning:
        logger.debug('Another repeater is already running; will not spawn '
                     'one.')
        return
    # We will now spawn a repeater in a subprocess at the same address as sock.
    # Make the address reusable so that, if the OS does not clean up sock
    # before the subprocess tries to bind to it, there is no conflict.
    try:
        reuse = socket.SO_REUSEADDR
    except AttributeError:
        warnings.warn("SO_REUSEADDR is not supported on this platform.")
    else:
        sock.setsockopt(socket.SOL_SOCKET, reuse, 1)
    logger.debug('Spawning caproto-repeater process....')
    try:
        subprocess.Popen(
            [sys.executable, '-m', 'caproto.commandline.repeater', '--quiet'],
            cwd="/")
    except Exception:
        logger.exception('Failed to spawn repeater.')
Ejemplo n.º 4
0
    def __init__(self, pvdb, interfaces=None):
        if interfaces is None:
            interfaces = ca.get_server_address_list()
        self.interfaces = interfaces
        self.udp_socks = {}  # map each interface to a UDP socket for searches
        self.beacon_socks = {}  # map each interface to a UDP socket for beacons
        self.pvdb = pvdb
        self.log = logging.getLogger(f'caproto.ctx.{id(self)}')

        self.circuits = set()
        self.broadcaster = ca.Broadcaster(our_role=ca.SERVER)

        self.subscriptions = defaultdict(deque)
        # Map Subscription to {'before': last_update, 'after': last_update}
        # to silence duplicates for Subscriptions that use edge-triggered sync
        # Channel Filter.
        self.last_sync_edge_update = defaultdict(lambda: defaultdict(dict))
        self.last_dead_band = {}
        self.beacon_count = 0

        self.environ = get_environment_variables()

        # ca_server_port: the default tcp/udp port from the environment
        self.ca_server_port = self.environ['EPICS_CA_SERVER_PORT']
        # the specific tcp port in use by this server
        self.port = None

        self.log.debug('EPICS_CA_SERVER_PORT set to %d. This is the UDP port '
                       'to be used for searches, and the first TCP server port'
                       ' to be tried.', self.ca_server_port)

        ignore_addresses = self.environ['EPICS_CAS_IGNORE_ADDR_LIST']
        self.ignore_addresses = ignore_addresses.split(' ')
Ejemplo n.º 5
0
    def __init__(self, pvdb, interfaces=None):
        if interfaces is None:
            interfaces = ca.get_server_address_list(
                protocol=ca.Protocol.PVAccess)
        self.interfaces = interfaces
        self.udp_socks = {}  # map each interface to a UDP socket for searches
        self.beacon_socks = {
        }  # map each interface to a UDP socket for beacons
        self.pvdb = pvdb
        self.log = logging.getLogger('caproto.pva.ctx')

        self.addresses = []
        self.circuits = set()
        self.authentication_methods = {'anonymous', 'ca'}

        self.environ = get_environment_variables()

        # pva_server_port: the default tcp/udp port from the environment
        self.pva_server_port = self.environ['EPICS_PVAS_SERVER_PORT']
        self.pva_broadcast_port = self.environ['EPICS_PVAS_BROADCAST_PORT']
        self.broadcaster = pva.Broadcaster(
            our_role=ca.SERVER,
            broadcast_port=self.pva_broadcast_port,
            server_port=None,  # TBD
        )
        # the specific tcp port in use by this server
        self.port = None

        self.log.debug(
            'EPICS_PVA_SERVER_PORT set to %d. This is the UDP port to be used'
            'for searches.')

        self.subscription_queue = None
        self.subscriptions = defaultdict(deque)
Ejemplo n.º 6
0
def test_server_addresses(monkeypatch, protocol, env_addr, expected):
    env = ca.get_environment_variables()
    key = ca.Protocol(protocol).server_env_key
    env[f'EPICS_{key}_INTF_ADDR_LIST'] = env_addr

    patch_env(monkeypatch, env)
    assert set(ca.get_server_address_list(protocol=protocol)) == set(expected)
Ejemplo n.º 7
0
async def run_epics_base_binary(*args):
    '''Run an EPICS-base binary with the environment variables set

    Returns
    -------
    stdout, stderr
        Decoded standard output and standard error text
    '''
    args = ['/usr/bin/env'] + list(args)

    print()
    print('* Executing', args)

    epics_env = ca.get_environment_variables()
    env = dict(PATH=os.environ['PATH'],
               EPICS_CA_AUTO_ADDR_LIST=epics_env['EPICS_CA_AUTO_ADDR_LIST'],
               EPICS_CA_ADDR_LIST=epics_env['EPICS_CA_ADDR_LIST'])

    p = curio.subprocess.Popen(args,
                               env=env,
                               stdout=curio.subprocess.PIPE,
                               stderr=curio.subprocess.PIPE)
    await p.wait()
    raw_stdout = await p.stdout.read()
    raw_stderr = await p.stderr.read()
    stdout = raw_stdout.decode('latin-1')
    stderr = raw_stderr.decode('latin-1')
    return stdout, stderr
Ejemplo n.º 8
0
async def run_epics_base_binary(backend, *args, max_attempts=3):
    '''Run an EPICS-base binary with the environment variables set

    Returns
    -------
    stdout, stderr
        Decoded standard output and standard error text
    '''
    if sys.platform == 'win32':
        args = list(args)
    else:
        args = ['/usr/bin/env'] + list(args)

    print()
    print('* Executing', args)

    epics_env = ca.get_environment_variables()
    env = os.environ.copy()
    env.update(PATH=os.environ['PATH'],
               EPICS_CA_AUTO_ADDR_LIST=epics_env['EPICS_CA_AUTO_ADDR_LIST'],
               EPICS_CA_ADDR_LIST=epics_env['EPICS_CA_ADDR_LIST'])

    def runner(attempt=0):
        e = os.environ.copy()
        e.update(env)
        with subprocess.Popen(args,
                              env=e,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE) as proc:
            raw_stdout, raw_stderr = proc.communicate()

        if b'Channel connect timeout' in raw_stderr:
            attempt += 1

            if attempt < max_attempts:
                return runner(attempt=attempt + 1)
        return raw_stdout, raw_stderr

    if backend == 'curio':
        raw_stdout, raw_stderr = await curio.run_in_thread(runner)
    elif backend == 'trio':
        raw_stdout, raw_stderr = await trio.run_sync_in_worker_thread(runner)
    elif backend == 'asyncio':
        loop = asyncio.get_event_loop()
        raw_stdout, raw_stderr = await loop.run_in_executor(None, runner)
    else:
        raise NotImplementedError('Unsupported async backend')

    stdout = raw_stdout.decode('latin-1')
    stderr = raw_stderr.decode('latin-1')
    return stdout, stderr
Ejemplo n.º 9
0
def test_beacon_addresses(monkeypatch, protocol, default_port, env_auto,
                          env_addr, expected):
    env = ca.get_environment_variables()

    key = ca.Protocol(protocol).server_env_key
    env[f'EPICS_{key}_BEACON_ADDR_LIST'] = env_addr
    env[f'EPICS_{key}_AUTO_BEACON_ADDR_LIST'] = env_auto
    if protocol == ca.Protocol.ChannelAccess:
        env['EPICS_CAS_BEACON_PORT'] = int(default_port)
    else:
        env['EPICS_PVAS_BROADCAST_PORT'] = int(default_port)

    patch_env(monkeypatch, env)
    assert set(ca.get_beacon_address_list(protocol=protocol)) == set(expected)
Ejemplo n.º 10
0
def run(host='0.0.0.0'):
    port = caproto.get_environment_variables()['EPICS_CA_REPEATER_PORT']
    addr = (host, port)
    logger.debug('Checking for another repeater....')

    try:
        sock = check_for_running_repeater(addr)
    except RepeaterAlreadyRunning:
        logger.info('Another repeater is already running; exiting.')
        return

    try:
        _run_repeater(sock, addr)
    except KeyboardInterrupt:
        logger.info('Keyboard interrupt; exiting.')
Ejemplo n.º 11
0
    def __init__(self):
        self.broadcaster = ca.Broadcaster(our_role=ca.CLIENT)
        self.log = self.broadcaster.log
        self.command_bundle_queue = curio.Queue()
        self.broadcaster_command_condition = curio.Condition()

        # UDP socket broadcasting to CA servers
        self.udp_sock = ca.bcast_socket(socket)
        self.registered = False  # refers to RepeaterRegisterRequest
        self.loop_ready_event = curio.Event()
        self.unanswered_searches = {}  # map search id (cid) to name
        self.search_results = {}  # map name to address

        self.environ = ca.get_environment_variables()
        self.ca_server_port = self.environ['EPICS_CA_SERVER_PORT']
Ejemplo n.º 12
0
def test_client_addresses(monkeypatch, protocol, default_port, env_auto,
                          env_addr, expected):
    env = ca.get_environment_variables()

    # Easier to test without netifaces
    monkeypatch.setattr(ca._utils, 'netifaces', None)

    env[f'EPICS_{protocol}_ADDR_LIST'] = env_addr
    env[f'EPICS_{protocol}_AUTO_ADDR_LIST'] = env_auto
    if protocol == 'CA':
        env['EPICS_CA_SERVER_PORT'] = int(default_port)
    elif protocol == 'PVA':
        env['EPICS_PVA_BROADCAST_PORT'] = int(default_port)

    patch_env(monkeypatch, env)
    assert set(ca.get_client_address_list(protocol=protocol)) == set(expected)
Ejemplo n.º 13
0
 def __init__(self):
     self._lock = threading.RLock()
     self.environ = ca.get_environment_variables()
     # map name to (time, address)
     self.beacon_log = logging.getLogger('caproto.bcast.beacon')
     self.search_log = logging.getLogger('caproto.bcast.search')
     self.name_to_addrs = collections.defaultdict(dict)
     self.addr_to_names = collections.defaultdict(set)
     self._searches = {}
     self._searches_by_name = {}
     self._unanswered_searches = {}
     self._last_beacon = {}
     self._search_id_counter = ca.ThreadsafeCounter(
         initial_value=random.randint(0, constants.MAX_ID),
         dont_clash_with=self._unanswered_searches,
     )
     self._search_id_counter.lock = self._lock  # use our lock
Ejemplo n.º 14
0
    def __init__(self, host, port, pvdb, *, log_level='ERROR'):
        self.host = host
        self.port = port
        self.pvdb = pvdb

        self.circuits = set()
        self.log_level = log_level
        self.broadcaster = ca.Broadcaster(our_role=ca.SERVER)
        self.broadcaster.log.setLevel(self.log_level)
        self.command_bundle_queue = curio.Queue()

        self.subscriptions = defaultdict(deque)
        self.subscription_queue = curio.UniversalQueue()
        self.beacon_count = 0
        self.environ = get_environment_variables()

        ignore_addresses = self.environ['EPICS_CAS_IGNORE_ADDR_LIST']
        self.ignore_addresses = ignore_addresses.split(' ')
Ejemplo n.º 15
0
    def __init__(self):
        self.broadcaster = ca.Broadcaster(our_role=ca.CLIENT)
        self.log = self.broadcaster.log
        self.command_bundle_queue = curio.Queue()
        self.broadcaster_command_condition = curio.Condition()

        # UDP socket broadcasting to CA servers
        self.udp_sock = ca.bcast_socket(socket)
        # Must bind or getsocketname() will raise on Windows.
        # See https://github.com/caproto/caproto/issues/514.
        self.udp_sock.bind(('', 0))
        self.broadcaster.our_address = safe_getsockname(self.udp_sock)
        self.registered = False  # refers to RepeaterRegisterRequest
        self.loop_ready_event = curio.Event()
        self.unanswered_searches = {}  # map search id (cid) to name
        self.search_results = {}  # map name to address

        self.environ = ca.get_environment_variables()
        self.ca_server_port = self.environ['EPICS_CA_SERVER_PORT']
Ejemplo n.º 16
0
    def __init__(self, pvdb, interfaces=None):
        if interfaces is None:
            interfaces = ca.get_server_address_list()
        self.interfaces = interfaces
        self.udp_socks = {}  # map each interface to a UDP socket for searches
        self.beacon_socks = {
        }  # map each interface to a UDP socket for beacons
        self.pvdb = pvdb
        self.log = logging.getLogger(f'caproto.ctx.{id(self)}')

        self.circuits = set()
        self.broadcaster = ca.Broadcaster(our_role=ca.SERVER)

        self.subscriptions = defaultdict(deque)
        # Map Subscription to {'before': last_update, 'after': last_update}
        # to silence duplicates for Subscriptions that use edge-triggered sync
        # Channel Filter.
        self.last_sync_edge_update = defaultdict(lambda: defaultdict(dict))
        self.last_dead_band = {}
        self.beacon_count = 0
        self.environ = get_environment_variables()

        ignore_addresses = self.environ['EPICS_CAS_IGNORE_ADDR_LIST']
        self.ignore_addresses = ignore_addresses.split(' ')
Ejemplo n.º 17
0
async def run_epics_base_binary(backend, *args):
    '''Run an EPICS-base binary with the environment variables set

    Returns
    -------
    stdout, stderr
        Decoded standard output and standard error text
    '''

    import sys
    if sys.platform == 'win32':
        args = list(args)
    else:
        args = ['/usr/bin/env'] + list(args)

    print()
    print('* Executing', args)

    epics_env = ca.get_environment_variables()
    env = os.environ.copy()
    env.update(PATH=os.environ['PATH'],
               EPICS_CA_AUTO_ADDR_LIST=epics_env['EPICS_CA_AUTO_ADDR_LIST'],
               EPICS_CA_ADDR_LIST=epics_env['EPICS_CA_ADDR_LIST'])

    def runner():
        e = os.environ.copy()
        e.update(env)
        pipes = subprocess.Popen(args,
                                 env=e,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
        return pipes.communicate()

    if backend == 'curio':
        if sys.platform == 'win32':
            raw_stdout, raw_stderr = await curio.run_in_thread(runner)
        else:
            p = curio.subprocess.Popen(args,
                                       env=env,
                                       stdout=curio.subprocess.PIPE,
                                       stderr=curio.subprocess.PIPE)
            await p.wait()
            raw_stdout = await p.stdout.read()
            raw_stderr = await p.stderr.read()
    elif backend == 'trio':
        raw_stdout, raw_stderr = await trio.run_sync_in_worker_thread(runner)
    elif backend == 'asyncio':
        loop = asyncio.get_event_loop()
        if sys.platform == 'win32':
            raw_stdout, raw_stderr = await loop.run_in_executor(None, runner)
        else:
            process = await asyncio.create_subprocess_exec(
                *args,
                env=env,
                loop=loop,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
            raw_stdout, raw_stderr = await process.communicate()
    else:
        raise NotImplementedError('Unsupported async backend')

    stdout = raw_stdout.decode('latin-1')
    stderr = raw_stderr.decode('latin-1')
    return stdout, stderr
Ejemplo n.º 18
0
    CLIENT, CONNECTED, DISCONNECTED, NEED_DATA, AddressTuple, Broadcaster,
    CaprotoError, ChannelFieldInfoResponse, ChannelGetResponse,
    ChannelMonitorResponse, ChannelPutResponse, ClientChannel,
    ClientVirtualCircuit, ConnectionValidatedResponse,
    ConnectionValidationRequest, CreateChannelResponse, ErrorResponseReceived,
    MonitorSubcommand, QOSFlags, SearchResponse, Subcommand, VirtualCircuit)

from ..._utils import safe_getsockname
from .._dataclass import (dataclass_from_field_desc, fill_dataclass,
                          is_pva_dataclass_instance)

# Make a dict to hold our tcp sockets.
sockets: Dict[VirtualCircuit, socket.socket] = {}
global_circuits: Dict[AddressTuple, VirtualCircuit] = {}

env = get_environment_variables()
logger = logging.getLogger('caproto.pva.ctx')
serialization_logger = logging.getLogger('caproto.pva.serialization_debug')


# Convenience functions that do both transport and caproto validation/ingest.
def send(circuit, command, pv_name=None):
    if pv_name is not None:
        tags = {'pv': pv_name}
    else:
        tags = None
    buffers_to_send = circuit.send(command, extra=tags)
    sockets[circuit].sendmsg(buffers_to_send)

    if serialization_logger.isEnabledFor(logging.DEBUG):
        to_send = b''.join(buffers_to_send)