diff --git a/drivers/linstor-manager b/drivers/linstor-manager index 2469b5060..6b45875d2 100755 --- a/drivers/linstor-manager +++ b/drivers/linstor-manager @@ -265,6 +265,19 @@ def force_destroy_drbd_volume(minor): if ret: raise Exception('Failed to destroy volume: {}'.format(stderr)) + +def get_ip_addr_of_pif(session, pif_uuid): + pif_ref = session.xenapi.PIF.get_by_uuid(pif_uuid) + pif = session.xenapi.PIF.get_record(pif_ref) + + if not pif['currently_attached']: + raise XenAPIPlugin.Failure('-1', ['PIF is not plugged']) + + ip_addr = pif['IP'] if pif['primary_address_type'].lower() == 'ipv4' else pif['IPv6'].split('/')[0] + if ip_addr == '': + raise XenAPIPlugin.Failure('-1', ['PIF has no IP']) + return ip_addr + # ------------------------------------------------------------------------------ @@ -983,15 +996,24 @@ def create_node_interface(session, args): name = args['name'] pif_uuid = args['pifUuid'] - pif_ref = session.xenapi.PIF.get_by_uuid(pif_uuid) - pif = session.xenapi.PIF.get_record(pif_ref) + ip_addr = get_ip_addr_of_pif(session, pif_uuid) - if not pif['currently_attached']: - raise XenAPIPlugin.Failure('-1', ['PIF is not plugged']) + linstor = LinstorVolumeManager( + get_controller_uri(), + group_name, + logger=util.SMlog + ) + try: + linstor.create_node_interface(hostname, name, ip_addr) + except Exception as e: + raise XenAPIPlugin.Failure('-1', [str(e)]) + return str(True) - ip_addr = pif['IP'] if pif['primary_address_type'].lower() == 'ipv4' else pif['IPv6'].split('/')[0] - if ip_addr == '': - raise XenAPIPlugin.Failure('-1', ['PIF has no IP']) + +def destroy_node_interface(session, args): + group_name = args['groupName'] + hostname = args['hostname'] + name = args['name'] linstor = LinstorVolumeManager( get_controller_uri(), @@ -999,12 +1021,47 @@ def create_node_interface(session, args): logger=util.SMlog ) try: - linstor.create_node_interface(hostname, name, ip_addr) + linstor.destroy_node_interface(hostname, name) except Exception as e: raise XenAPIPlugin.Failure('-1', [str(e)]) return str(True) +def modify_node_interface(session, args): + group_name = args['groupName'] + hostname = args['hostname'] + name = args['name'] + pif_uuid = args['pifUuid'] + + ip_addr = get_ip_addr_of_pif(session, pif_uuid) + + linstor = LinstorVolumeManager( + get_controller_uri(), + group_name, + logger=util.SMlog + ) + try: + linstor.modify_node_interface(hostname, name, ip_addr) + except Exception as e: + raise XenAPIPlugin.Failure('-1', [str(e)]) + return str(True) + + +def list_node_interfaces(session, args): + group_name = args['groupName'] + hostname = args['hostname'] + + linstor = LinstorVolumeManager( + get_controller_uri(), + group_name, + logger=util.SMlog + ) + try: + return json.dumps(linstor.list_node_interfaces(hostname)) + except Exception as e: + raise XenAPIPlugin.Failure('-1', [str(e)]) + + def set_node_preferred_interface(session, args): group_name = args['groupName'] hostname = args['hostname'] @@ -1072,5 +1129,8 @@ if __name__ == '__main__': 'healthCheck': health_check, 'createNodeInterface': create_node_interface, + 'destroyNodeInterface': destroy_node_interface, + 'modifyNodeInterface': modify_node_interface, + 'listNodeInterfaces': list_node_interfaces, 'setNodePreferredInterface': set_node_preferred_interface }) diff --git a/drivers/linstorvolumemanager.py b/drivers/linstorvolumemanager.py index a41314e53..32d153342 100755 --- a/drivers/linstorvolumemanager.py +++ b/drivers/linstorvolumemanager.py @@ -872,7 +872,6 @@ def get_volume_size(self, volume_uuid): ) return size * 1024 - def set_auto_promote_timeout(self, volume_uuid, timeout): """ Define the blocking time of open calls when a DRBD @@ -1120,7 +1119,6 @@ def get_volume_openers(self, volume_uuid): """ return get_all_volume_openers(self.get_volume_name(volume_uuid), '0') - def get_volumes_with_name(self): """ Give a volume dictionnary that contains names actually owned. @@ -1529,21 +1527,93 @@ def destroy_node(self, node_name): 'Failed to destroy node `{}`: {}'.format(node_name, error_str) ) - def create_node_interface(self, hostname, name, ip_addr): - result = self._linstor.netinterface_create(hostname, name, ip_addr) - if not linstor.Linstor.all_api_responses_no_error(result): + def create_node_interface(self, node_name, name, ip): + """ + Create a new node interface in the LINSTOR database. + :param str node_name: Node name of the interface to use. + :param str name: Interface to create. + :param str ip: IP of the interface. + """ + result = self._linstor.netinterface_create(node_name, name, ip) + errors = self._filter_errors(result) + if errors: + error_str = self._get_error_str(errors) raise LinstorVolumeManagerError( - 'Unable to create interface on `{}`: {}'.format(hostname, ', '.join( - [str(x) for x in result])) - ) + 'Failed to create node interface on `{}`: {}'.format(node_name, error_str) + ) - def set_node_preferred_interface(self, hostname, name): - result = self._linstor.node_modify(hostname, property_dict={'PrefNic': name}) - if not linstor.Linstor.all_api_responses_no_error(result): + def destroy_node_interface(self, node_name, name): + """ + Destroy a node interface in the LINSTOR database. + :param str node_name: Node name of the interface to remove. + :param str name: Interface to remove. + """ + result = self._linstor.netinterface_delete(node_name, name) + errors = self._filter_errors(result) + if errors: + error_str = self._get_error_str(errors) raise LinstorVolumeManagerError( - 'Unable to set preferred interface on `{}`: {}'.format(hostname, ', '.join( - [str(x) for x in result])) - ) + 'Failed to destroy node interface on `{}`: {}'.format(node_name, error_str) + ) + + def modify_node_interface(self, node_name, name, ip): + """ + Modify a node interface in the LINSTOR database. Create it if necessary. + :param str node_name: Node name of the interface to use. + :param str name: Interface to modify or create. + :param str ip: IP of the interface. + """ + result = self._linstor.netinterface_create(node_name, name, ip) + errors = self._filter_errors(result) + if not errors: + return + + if self._check_errors(errors, [linstor.consts.FAIL_EXISTS_NET_IF]): + result = self._linstor.netinterface_modify(node_name, name, ip) + errors = self._filter_errors(result) + if not errors: + return + + error_str = self._get_error_str(errors) + raise LinstorVolumeManagerError( + 'Unable to modify interface on `{}`: {}'.format(node_name, error_str) + ) + + def list_node_interfaces(self, node_name): + """ + List all node interfaces. + :param str node_name: Node name to use to list interfaces. + :rtype: list + : + """ + result = self._linstor.net_interface_list(node_name) + if not result: + raise LinstorVolumeManagerError( + 'Unable to list interfaces on `{}`: no list received'.format(node_name) + ) + + interfaces = {} + for interface in result: + interface = interface._rest_data + interfaces[interface['name']] = { + 'address': interface['address'], + 'active': interface['is_active'] + } + return interfaces + + def set_node_preferred_interface(self, node_name, name): + """ + Set the preferred interface to use on a node. + :param str node_name: Node name of the interface. + :param str name: Preferred interface to use. + """ + result = self._linstor.node_modify(node_name, property_dict={'PrefNic': name}) + errors = self._filter_errors(result) + if errors: + error_str = self._get_error_str(errors) + raise LinstorVolumeManagerError( + 'Failed to set preferred node interface on `{}`: {}'.format(node_name, error_str) + ) def get_nodes_info(self): """