def run(self, context, args, kwargs, opargs): # Enclose ipv6 urls in '[]' according to ipv6 url spec my_ips = [ wrap_address(ip) for ip in context.call_sync('network.config.get_my_ips', timeout=60) ] my_protocols = context.call_sync('system.ui.get_config', timeout=60) urls = [] for proto in my_protocols['webui_protocol']: proto_port = my_protocols['webui_{0}_port'.format(proto.lower())] if proto_port is not None: if proto_port in [80, 443]: for x in my_ips: urls.append( {'url': '{0}://{1}'.format(proto.lower(), x)}) else: for x in my_ips: urls.append({ 'url': '{0}://{1}:{2}'.format(proto.lower(), x, proto_port) }) return Sequence( _("You may try the following URLs to access the web user interface:" ), Table(urls, [Table.Column(_('URLs (url)'), 'url')]))
def connect(self, url, parent, **kwargs): """ Open a connection. Args: url (ParseResult): The url to open. parent (Connection): The connection wrapper class object. Kwargs: username (str): The username to login with. hostname (str): The hostname to connect to. port (int): The port to connect to. Raises: RuntimeError, ValueError """ self.scheme_default_port = 80 self.parent = parent self.username = url.username self.port = url.port if url.hostname: self.hostname = url.hostname elif url.netloc: self.hostname = url.netloc if '@' in self.hostname: temp, self.hostname = self.hostname.split('@') elif url.path: self.hostname = url.path if not self.parent: raise RuntimeError('ClientTransportWS can be only created inside of a class') if not self.username: self.username = kwargs.get('username', None) else: if 'username' in kwargs: raise ValueError('Username cannot be delared in both url and arguments.') if self.username: raise ValueError('Username cannot be delared at this state for ws transport type.') if not self.hostname: self.hostname = kwargs.get('hostname', "127.0.0.1") else: if 'hostname' in kwargs: raise ValueError('Host name cannot be delared in both url and arguments.') if not self.port: self.port = kwargs.get('port', self.scheme_default_port) else: if 'port' in kwargs: raise ValueError('Port cannot be delared in both url and arguments.') ws_url = 'ws://{0}:{1}/dispatcher/socket'.format(wrap_address(self.hostname), self.port) self.ws = self.WebSocketHandler(ws_url, self) self.ws.connect() self.opened.wait()
def run(self, context, args, kwargs, opargs): # Enclose ipv6 urls in '[]' according to ipv6 url spec my_ips = [wrap_address(ip) for ip in context.call_sync('network.config.get_my_ips', timeout=60)] my_protocols = context.call_sync('system.ui.get_config', timeout=60) urls = [] for proto in my_protocols['webui_protocol']: proto_port = my_protocols['webui_{0}_port'.format(proto.lower())] if proto_port is not None: if proto_port in [80, 443]: for x in my_ips: urls.append({'url': '{0}://{1}'.format(proto.lower(), x)}) else: for x in my_ips: urls.append({'url': '{0}://{1}:{2}'.format(proto.lower(), x, proto_port)}) return Table(urls, [Table.Column(_('Web interface URLs'), 'url')])
def get_freenas_peer_client(parent, remote): try: address = socket.gethostbyname(remote) except socket.error as err: raise TaskException(err.errno, '{0} is unreachable'.format(remote)) host = parent.dispatcher.call_sync( 'peer.query', [ ('or', [ ('credentials.address', '=', remote), ('credentials.address', '=', address), ]), ('type', '=', 'freenas') ], {'single': True} ) if not host: raise TaskException(errno.ENOENT, 'There are no known keys to connect to {0}'.format(remote)) with io.StringIO() as f: f.write(parent.configstore.get('peer.freenas.key.private')) f.seek(0) pkey = RSAKey.from_private_key(f) credentials = host['credentials'] try: client = Client() with tempfile.NamedTemporaryFile('w') as host_key_file: host_key_file.write(remote + ' ' + credentials['hostkey']) host_key_file.flush() client.connect( 'ws+ssh://freenas@{0}'.format(wrap_address(remote)), port=credentials['port'], host_key_file=host_key_file.name, pkey=pkey ) client.login_service('replicator') return client except (AuthenticationException, SSHException): raise TaskException(errno.EAUTH, 'Cannot connect to {0}'.format(remote)) except OSError as err: raise TaskException(errno.ECONNREFUSED, 'Cannot connect to {0}: {1}'.format(remote, err))
def run(self, peer, initial_credentials): hostid = self.dispatcher.call_sync('system.info.host_uuid') hostname = self.dispatcher.call_sync( 'system.general.get_config')['hostname'] remote_peer_name = hostname credentials = peer['credentials'] remote = credentials.get('address') port = credentials.get('port', 22) username = initial_credentials.get('username') password = initial_credentials.get('password') auth_code = initial_credentials.get('auth_code') key_auth = initial_credentials.get('key_auth') local_ssh_config = self.dispatcher.call_sync('service.sshd.get_config') if self.datastore.exists('peers', ('credentials.address', '=', remote), ('type', '=', 'freenas')): raise TaskException( errno.EEXIST, 'FreeNAS peer entry for {0} already exists'.format(remote)) remote_client = Client() try: if auth_code: try: remote_client.connect('ws://{0}'.format( wrap_address(remote))) except (AuthenticationException, OSError, ConnectionRefusedError): raise TaskException( errno.ECONNABORTED, 'Cannot connect to {0}:{1}'.format(remote, port)) try: remote_host_uuid, pubkey = remote_client.call_sync( 'peer.freenas.auth_with_code', auth_code, hostname, local_ssh_config['port']) except RpcException as err: raise TaskException(err.code, err.message) try: self.dispatcher.call_sync('peer.freenas.put_temp_pubkey', pubkey) if not self.dispatcher.test_or_wait_for_event( 'peer.changed', lambda ar: ar['operation'] == 'create' and remote_host_uuid in ar['ids'], lambda: self.datastore.exists( 'peers', ('id', '=', remote_host_uuid)), timeout=30): raise TaskException( errno.EAUTH, 'FreeNAS peer creation failed. Check connection to host {0}.' .format(remote)) finally: self.dispatcher.call_sync( 'peer.freenas.remove_temp_pubkey', pubkey) else: try: if key_auth: with io.StringIO() as f: f.write( self.configstore.get( 'peer.freenas.key.private')) f.seek(0) pkey = RSAKey.from_private_key(f) max_tries = 50 while True: try: remote_client.connect( 'ws+ssh://freenas@{0}'.format( wrap_address(remote)), pkey=pkey, port=port) break except AuthenticationException: if max_tries: max_tries -= 1 time.sleep(1) else: raise else: remote_client.connect('ws+ssh://{0}@{1}'.format( username, wrap_address(remote)), port=port, password=password) remote_client.login_service('replicator') except (AuthenticationException, OSError, ConnectionRefusedError): raise TaskException( errno.ECONNABORTED, 'Cannot connect to {0}:{1}'.format(remote, port)) local_host_key, local_pub_key = self.dispatcher.call_sync( 'peer.freenas.get_ssh_keys') remote_host_key, remote_pub_key = remote_client.call_sync( 'peer.freenas.get_ssh_keys') ip_at_remote_side = remote_client.local_address[0] remote_hostname = remote_client.call_sync( 'system.general.get_config')['hostname'] remote_host_key = remote_host_key.rsplit(' ', 1)[0] local_host_key = local_host_key.rsplit(' ', 1)[0] if remote_client.call_sync('peer.query', [('id', '=', hostid)]): raise TaskException( errno.EEXIST, 'Peer entry of {0} already exists at {1}'.format( hostname, remote)) peer['credentials'] = { '%type': 'freenas-credentials', 'pubkey': remote_pub_key, 'hostkey': remote_host_key, 'port': port, 'address': remote_hostname } local_id = remote_client.call_sync('system.info.host_uuid') peer['id'] = local_id peer['name'] = remote_hostname ip = socket.gethostbyname(remote) created_ids = self.join_subtasks( self.run_subtask('peer.freenas.create_local', peer, ip, True)) peer['id'] = hostid peer['name'] = remote_peer_name peer['credentials'] = { '%type': 'freenas-credentials', 'pubkey': local_pub_key, 'hostkey': local_host_key, 'port': local_ssh_config['port'], 'address': hostname } try: call_task_and_check_state(remote_client, 'peer.freenas.create_local', peer, ip_at_remote_side) except TaskException: self.datastore.delete('peers', local_id) self.dispatcher.dispatch_event('peer.changed', { 'operation': 'delete', 'ids': [local_id] }) raise return created_ids[0] finally: remote_client.disconnect()
def run(self, peer, initial_credentials): hostid = self.dispatcher.call_sync('system.info.host_uuid') hostname = self.dispatcher.call_sync('system.general.get_config')['hostname'] remote_peer_name = hostname credentials = peer['credentials'] remote = credentials.get('address') port = credentials.get('port', 22) username = initial_credentials.get('username') password = initial_credentials.get('password') auth_code = initial_credentials.get('auth_code') key_auth = initial_credentials.get('key_auth') local_ssh_config = self.dispatcher.call_sync('service.sshd.get_config') if self.datastore.exists('peers', ('credentials.address', '=', remote), ('type', '=', 'freenas')): raise TaskException( errno.EEXIST, 'FreeNAS peer entry for {0} already exists'.format(remote) ) remote_client = Client() try: if auth_code: try: remote_client.connect('ws://{0}'.format(wrap_address(remote))) except (AuthenticationException, OSError, ConnectionRefusedError): raise TaskException(errno.ECONNABORTED, 'Cannot connect to {0}:{1}'.format(remote, port)) try: remote_host_uuid, pubkey = remote_client.call_sync( 'peer.freenas.auth_with_code', auth_code, hostname, local_ssh_config['port'] ) except RpcException as err: raise TaskException(err.code, err.message) try: self.dispatcher.call_sync('peer.freenas.put_temp_pubkey', pubkey) if not self.dispatcher.test_or_wait_for_event( 'peer.changed', lambda ar: ar['operation'] == 'create' and remote_host_uuid in ar['ids'], lambda: self.datastore.exists('peers', ('id', '=', remote_host_uuid)), timeout=30 ): raise TaskException( errno.EAUTH, 'FreeNAS peer creation failed. Check connection to host {0}.'.format(remote) ) finally: self.dispatcher.call_sync('peer.freenas.remove_temp_pubkey', pubkey) else: try: if key_auth: with io.StringIO() as f: f.write(self.configstore.get('peer.freenas.key.private')) f.seek(0) pkey = RSAKey.from_private_key(f) max_tries = 50 while True: try: remote_client.connect('ws+ssh://freenas@{0}'.format( wrap_address(remote)), pkey=pkey, port=port ) break except AuthenticationException: if max_tries: max_tries -= 1 time.sleep(1) else: raise else: remote_client.connect( 'ws+ssh://{0}@{1}'.format(username, wrap_address(remote)), port=port, password=password ) remote_client.login_service('replicator') except (AuthenticationException, OSError, ConnectionRefusedError): raise TaskException(errno.ECONNABORTED, 'Cannot connect to {0}:{1}'.format(remote, port)) local_host_key, local_pub_key = self.dispatcher.call_sync('peer.freenas.get_ssh_keys') remote_host_key, remote_pub_key = remote_client.call_sync('peer.freenas.get_ssh_keys') ip_at_remote_side = remote_client.local_address[0] remote_hostname = remote_client.call_sync('system.general.get_config')['hostname'] remote_host_key = remote_host_key.rsplit(' ', 1)[0] local_host_key = local_host_key.rsplit(' ', 1)[0] if remote_client.call_sync('peer.query', [('id', '=', hostid)]): raise TaskException(errno.EEXIST, 'Peer entry of {0} already exists at {1}'.format(hostname, remote)) peer['credentials'] = { '%type': 'freenas-credentials', 'pubkey': remote_pub_key, 'hostkey': remote_host_key, 'port': port, 'address': remote_hostname } local_id = remote_client.call_sync('system.info.host_uuid') peer['id'] = local_id peer['name'] = remote_hostname ip = socket.gethostbyname(remote) created_id = self.run_subtask_sync( 'peer.freenas.create_local', peer, ip, True ) peer['id'] = hostid peer['name'] = remote_peer_name peer['credentials'] = { '%type': 'freenas-credentials', 'pubkey': local_pub_key, 'hostkey': local_host_key, 'port': local_ssh_config['port'], 'address': hostname } try: call_task_and_check_state( remote_client, 'peer.freenas.create_local', peer, ip_at_remote_side ) except TaskException: self.datastore.delete('peers', local_id) self.dispatcher.dispatch_event('peer.changed', { 'operation': 'delete', 'ids': [local_id] }) raise return created_id finally: remote_client.disconnect()
def connect(self, url, parent, **kwargs): """ Open a connection. Args: url (ParseResult): The url to open. parent (Connection): The connection wrapper class object. Kwargs: username (str): The username to login with. hostname (str): The hostname to connect to. port (int): The port to connect to. Raises: RuntimeError, ValueError """ self.scheme_default_port = 80 self.parent = parent self.username = url.username self.port = url.port if url.hostname: self.hostname = url.hostname elif url.netloc: self.hostname = url.netloc if '@' in self.hostname: temp, self.hostname = self.hostname.split('@') elif url.path: self.hostname = url.path if not self.parent: raise RuntimeError( 'ClientTransportWS can be only created inside of a class') if not self.username: self.username = kwargs.get('username', None) else: if 'username' in kwargs: raise ValueError( 'Username cannot be delared in both url and arguments.') if self.username: raise ValueError( 'Username cannot be delared at this state for ws transport type.' ) if not self.hostname: self.hostname = kwargs.get('hostname', "127.0.0.1") else: if 'hostname' in kwargs: raise ValueError( 'Host name cannot be delared in both url and arguments.') if not self.port: self.port = kwargs.get('port', self.scheme_default_port) else: if 'port' in kwargs: raise ValueError( 'Port cannot be delared in both url and arguments.') ws_url = 'ws://{0}:{1}/dispatcher/socket'.format( wrap_address(self.hostname), self.port) self.ws = self.WebSocketHandler(ws_url, self) self.ws.connect() self.opened.wait()