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)
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)
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.')
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(' ')
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)
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)
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
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
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)
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.')
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']
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)
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
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(' ')
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']
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(' ')
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
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)