def run(self, id): peer = self.datastore.get_by_id('peers', id) if not peer: raise TaskException(errno.ENOENT, 'Peer entry {0} does not exist'.format(id)) remote = q.get(peer, 'credentials.address') remote_client = None hostid = self.dispatcher.call_sync('system.info.host_uuid') try: try: remote_client = get_freenas_peer_client(self, remote) call_task_and_check_state(remote_client, 'peer.freenas.delete_local', hostid, False) except RpcException as e: self.add_warning( TaskWarning( e.code, 'Remote {0} is unreachable. Delete operation is performed at local side only.' .format(remote))) except ValueError as e: self.add_warning(TaskWarning(errno.EINVAL, str(e))) self.join_subtasks( self.run_subtask('peer.freenas.delete_local', id, True)) finally: if remote_client: remote_client.disconnect()
def run(self, id, port): peer = self.datastore.get_by_id('peers', id) remote_client = None if not peer: raise TaskException(errno.ENOENT, 'Replication peer entry {0} does not exist'.format(id)) try: remote_client = get_replication_client(self.dispatcher, peer['address']) remote_peer = remote_client.call_sync('peer.query', [('id', '=', peer['id'])], {'single': True}) if not remote_peer: raise TaskException(errno.ENOENT, 'Remote side of peer {0} does not exist'.format(peer['name'])) remote_peer['credentials']['port'] = port call_task_and_check_state( remote_client, 'peer.replication.delete_local', id ) call_task_and_check_state( remote_client, 'peer.replication.create_local', remote_peer ) finally: if remote_client: remote_client.disconnect()
def run(self, id): peer = self.datastore.get_by_id('peers', id) if not peer: raise TaskException(errno.ENOENT, 'Peer entry {0} does not exist'.format(id)) remote = peer['address'] remote_client = None try: try: remote_client = get_replication_client(self.dispatcher, remote) call_task_and_check_state( remote_client, 'peer.replication.delete_local', id ) except RpcException as e: self.add_warning(TaskWarning( e.code, 'Remote {0} is unreachable. Delete operation is performed at local side only.'.format(remote) )) except ValueError as e: self.add_warning(TaskWarning( errno.EINVAL, str(e) )) self.join_subtasks(self.run_subtask( 'peer.replication.delete_local', id )) finally: if remote_client: remote_client.disconnect()
def run(self, id): peer = self.datastore.get_by_id('peers', id) hostid = self.dispatcher.call_sync('system.info.host_uuid') remote_client = None if not peer: raise TaskException( errno.ENOENT, 'FreeNAS peer entry {0} does not exist'.format(id)) try: remote_client = get_freenas_peer_client( self, peer['credentials']['address']) remote_peer = remote_client.call_sync('peer.query', [('id', '=', hostid)], {'single': True}) if not remote_peer: raise TaskException( errno.ENOENT, 'Remote side of peer {0} does not exist'.format( peer['name'])) ip_at_remote_side = remote_client.local_address[0] hostname = self.dispatcher.call_sync( 'system.general.get_config')['hostname'] port = self.dispatcher.call_sync('service.sshd.get_config')['port'] remote_peer['name'] = hostname remote_peer['credentials']['port'] = port remote_peer['credentials']['address'] = hostname call_task_and_check_state(remote_client, 'peer.freenas.delete_local', hostid) remote_peer = exclude(remote_peer, 'created_at', 'updated_at') call_task_and_check_state(remote_client, 'peer.freenas.create_local', remote_peer, ip_at_remote_side) finally: if remote_client: remote_client.disconnect()
def run(self, id): peer = self.datastore.get_by_id('peers', id) hostid = self.dispatcher.call_sync('system.info.host_uuid') remote_client = None if not peer: raise TaskException(errno.ENOENT, 'FreeNAS peer entry {0} does not exist'.format(id)) try: remote_client = get_freenas_peer_client(self, peer['credentials']['address']) remote_peer = remote_client.call_sync('peer.query', [('id', '=', hostid)], {'single': True}) if not remote_peer: raise TaskException(errno.ENOENT, 'Remote side of peer {0} does not exist'.format(peer['name'])) ip_at_remote_side = remote_client.local_address[0] hostname = self.dispatcher.call_sync('system.general.get_config')['hostname'] port = self.dispatcher.call_sync('service.sshd.get_config')['port'] remote_peer['name'] = hostname remote_peer['credentials']['port'] = port remote_peer['credentials']['address'] = hostname call_task_and_check_state( remote_client, 'peer.freenas.delete_local', hostid ) remote_peer = exclude(remote_peer, 'created_at', 'updated_at') call_task_and_check_state( remote_client, 'peer.freenas.create_local', remote_peer, ip_at_remote_side ) finally: if remote_client: remote_client.disconnect()
def run(self, id): peer = self.datastore.get_by_id('peers', id) if not peer: raise TaskException(errno.ENOENT, 'Peer entry {0} does not exist'.format(id)) remote = q.get(peer, 'credentials.address') remote_client = None hostid = self.dispatcher.call_sync('system.info.host_uuid') try: try: remote_client = get_freenas_peer_client(self, remote) call_task_and_check_state( remote_client, 'peer.freenas.delete_local', hostid, False ) except RpcException as e: self.add_warning(TaskWarning( e.code, 'Remote {0} is unreachable. Delete operation is performed at local side only.'.format(remote) )) except ValueError as e: self.add_warning(TaskWarning( errno.EINVAL, str(e) )) self.run_subtask_sync( 'peer.freenas.delete_local', id, True ) finally: if remote_client: 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_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 run(self, peer): if self.datastore.exists('peers', ('address', '=', peer['address']), ('type', '=', 'replication')): raise TaskException(errno.EEXIST, 'Replication peer entry for {0} already exists'.format(peer['address'])) if peer['credentials']['type'] != 'ssh': raise TaskException(errno.EINVAL, 'SSH credentials type is needed to perform replication peer pairing') remote = peer.get('address') credentials = peer['credentials'] username = credentials.get('username') port = credentials.get('port', 22) password = credentials.get('password') if not username: raise TaskException(errno.EINVAL, 'Username has to be specified') if not remote: raise TaskException(errno.EINVAL, 'Address of remote host has to be specified') if not password: raise TaskException(errno.EINVAL, 'Password has to be specified') remote_client = Client() try: try: remote_client.connect('ws+ssh://{0}@{1}'.format(username, 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_keys = self.dispatcher.call_sync('peer.get_ssh_keys') remote_keys = remote_client.call_sync('peer.get_ssh_keys') ip_at_remote_side = remote_client.call_sync('management.get_sender_address').split(',', 1)[0] remote_host_key = remote + ' ' + remote_keys[0].rsplit(' ', 1)[0] local_host_key = ip_at_remote_side + ' ' + local_keys[0].rsplit(' ', 1)[0] local_ssh_config = self.dispatcher.call_sync('service.sshd.get_config') if remote_client.call_sync('peer.query', [('name', '=', peer['name'])]): raise TaskException(errno.EEXIST, 'Peer entry {0} already exists at {1}'.format(peer['name'], remote)) peer['credentials'] = { 'pubkey': remote_keys[1], 'hostkey': remote_host_key, 'port': port, 'type': 'replication' } self.join_subtasks(self.run_subtask( 'peer.replication.create_local', peer )) peer['address'] = ip_at_remote_side peer['credentials'] = { 'pubkey': local_keys[1], 'hostkey': local_host_key, 'port': local_ssh_config['port'], 'type': 'replication' } id = self.datastore.query('peers', ('name', '=', peer['name']), select='id') try: call_task_and_check_state( remote_client, 'peer.replication.create_local', peer ) except TaskException: self.datastore.delete('peers', id) self.dispatcher.dispatch_event('peer.changed', { 'operation': 'delete', 'ids': [id] }) raise finally: remote_client.disconnect()