963 'zfs_volume_base': self.configuration.zfs_volume_base, |
963 'zfs_volume_base': self.configuration.zfs_volume_base, |
964 'san_info': san_info}) |
964 'san_info': san_info}) |
965 |
965 |
966 return status |
966 return status |
967 |
967 |
968 def check_for_setup_error(self): |
968 def do_setup(self, context): |
969 """Check the setup error.""" |
969 """Check wwns and setup the target group.""" |
970 wwns = self._get_wwns() |
970 self.wwns = self._get_wwns() |
971 if not wwns: |
971 if not self.wwns: |
972 msg = (_("Could not determine fibre channel world wide " |
972 msg = (_("Could not determine fibre channel world wide " |
973 "node names.")) |
973 "node names.")) |
974 raise exception.VolumeBackendAPIException(data=msg) |
974 raise exception.VolumeBackendAPIException(data=msg) |
|
975 |
|
976 self.tg = 'tg-wwn-%s' % self.wwns[0] |
|
977 if not self._check_tg(self.tg): |
|
978 self._setup_tg(self.tg) |
975 |
979 |
976 def _get_wwns(self): |
980 def _get_wwns(self): |
977 """Get the FC port WWNs of the host.""" |
981 """Get the FC port WWNs of the host.""" |
978 (out, _err) = self._execute('/usr/sbin/fcinfo', 'hba-port', '-t') |
982 (out, _err) = self._execute('/usr/sbin/fcinfo', 'hba-port', '-t') |
979 |
983 |
984 LOG.debug(_("Got the FC port WWN '%s'") % wwn) |
988 LOG.debug(_("Got the FC port WWN '%s'") % wwn) |
985 wwns.append(wwn) |
989 wwns.append(wwn) |
986 |
990 |
987 return wwns |
991 return wwns |
988 |
992 |
989 def _check_wwn_tg(self, wwn): |
993 def _get_target_wwns(self, tg): |
990 """Check if the target group 'tg-wwn-xxx' exists.""" |
994 """Get the target members in the tg.""" |
991 (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-tg') |
995 (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-tg', |
992 |
996 '-v', tg) |
|
997 |
|
998 wwns = [] |
993 for line in [l.strip() for l in out.splitlines()]: |
999 for line in [l.strip() for l in out.splitlines()]: |
994 if line.startswith("Target Group:") and wwn in line: |
1000 if line.startswith("Member:"): |
995 tg = line.split()[-1] |
1001 wwn = line.split()[-1] |
996 break |
1002 target_wwn = wwn.split('.')[-1] |
997 else: |
1003 wwns.append(target_wwn) |
998 LOG.debug(_("The target group 'tg-wwn-%s' doesn't exist.") % wwn) |
1004 return wwns |
999 tg = None |
1005 |
1000 |
1006 def _setup_tg(self, tg): |
1001 return tg |
1007 """Setup the target group.""" |
|
1008 self._stmf_execute('/usr/sbin/stmfadm', 'create-tg', tg) |
|
1009 |
|
1010 # Add free target wwns into the target group |
|
1011 for wwn in self.wwns: |
|
1012 if not self._target_in_tg(wwn, None): |
|
1013 target_wwn = 'wwn.%s' % wwn |
|
1014 try: |
|
1015 self._stmf_execute('/usr/sbin/stmfadm', 'offline-target', |
|
1016 target_wwn) |
|
1017 self._stmf_execute('/usr/sbin/stmfadm', 'add-tg-member', |
|
1018 '-g', tg, target_wwn) |
|
1019 self._stmf_execute('/usr/sbin/stmfadm', 'online-target', |
|
1020 target_wwn) |
|
1021 assert self._check_target(wwn, 'Channel') == 'Online' |
|
1022 |
|
1023 except: |
|
1024 LOG.error(_LE("Failed to add and online the target '%s'.") |
|
1025 % (target_wwn)) |
|
1026 |
|
1027 target_wwns = self._get_target_wwns(tg) |
|
1028 if not target_wwns: |
|
1029 msg = (_("No target members exist in the target group '%s'.") |
|
1030 % tg) |
|
1031 raise exception.VolumeBackendAPIException(data=msg) |
1002 |
1032 |
1003 def _only_lu(self, lu): |
1033 def _only_lu(self, lu): |
1004 """Check if the LU is the only one.""" |
1034 """Check if the LU is the only one.""" |
1005 (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-lu', '-v') |
1035 (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-lu', '-v') |
1006 linecount = 0 |
1036 linecount = 0 |
1023 if tg is not None: |
1053 if tg is not None: |
1024 (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-tg', |
1054 (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-tg', |
1025 '-v', tg) |
1055 '-v', tg) |
1026 else: |
1056 else: |
1027 (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-tg', '-v') |
1057 (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-tg', '-v') |
1028 |
|
1029 for line in [l.strip() for l in out.splitlines()]: |
1058 for line in [l.strip() for l in out.splitlines()]: |
1030 if line.startswith("Member:") and target in line: |
1059 if line.startswith("Member:") and target in line: |
1031 return True |
1060 return True |
1032 LOG.debug(_("The target '%s' is not in any target group.") % target) |
1061 LOG.debug(_("The target '%s' is not in %s target group.") % |
|
1062 (target, tg if tg else 'any')) |
1033 return False |
1063 return False |
|
1064 |
|
1065 def _force_lip_wwn(self): |
|
1066 """Force the link to reinitialize.""" |
|
1067 target_wwns = self._get_target_wwns(self.tg) |
|
1068 for target_wwn in target_wwns: |
|
1069 self._stmf_execute('/usr/sbin/fcadm', 'force-lip', target_wwn) |
1034 |
1070 |
1035 def create_export(self, context, volume): |
1071 def create_export(self, context, volume): |
1036 """Export the volume.""" |
1072 """Export the volume.""" |
1037 # If the volume is already exported there is nothing to do, as we |
1073 # If the volume is already exported there is nothing to do, as we |
1038 # simply export volumes and they are universally available. |
1074 # simply export volumes and they are universally available. |
1045 msg = (_("Failed to create logical unit for volume '%s' due " |
1081 msg = (_("Failed to create logical unit for volume '%s' due " |
1046 "to an existing LU id but no view.") % volume['name']) |
1082 "to an existing LU id but no view.") % volume['name']) |
1047 raise exception.VolumeBackendAPIException(data=msg) |
1083 raise exception.VolumeBackendAPIException(data=msg) |
1048 |
1084 |
1049 zvol = self._get_zvol_path(volume) |
1085 zvol = self._get_zvol_path(volume) |
1050 |
|
1051 # Create a Logical Unit (LU) |
1086 # Create a Logical Unit (LU) |
1052 self._stmf_execute('/usr/sbin/stmfadm', 'create-lu', zvol) |
1087 self._stmf_execute('/usr/sbin/stmfadm', 'create-lu', zvol) |
1053 luid = self._get_luid(volume) |
1088 luid = self._get_luid(volume) |
1054 if not luid: |
1089 if not luid: |
1055 msg = (_("Failed to create logic unit for volume '%s'") |
1090 msg = (_("Failed to create logic unit for volume '%s'") |
1056 % volume['name']) |
1091 % volume['name']) |
1057 raise exception.VolumeBackendAPIException(data=msg) |
1092 raise exception.VolumeBackendAPIException(data=msg) |
1058 |
1093 |
1059 wwns = self._get_wwns() |
1094 # setup the target group if it doesn't exist. |
1060 wwn = wwns[0] |
1095 if not self._check_tg(self.tg): |
1061 target_group = self._check_wwn_tg(wwn) |
1096 self._setup_tg(self.tg) |
1062 if target_group is None: |
|
1063 target_group = 'tg-wwn-%s' % wwn |
|
1064 if self._target_in_tg(wwn, None): |
|
1065 msg = (_("Target WWN '%s' has been found in another" |
|
1066 "target group, so it will not be added " |
|
1067 "into the expected target group '%s'.") % |
|
1068 (wwn, target_group)) |
|
1069 raise exception.VolumeBackendAPIException(data=msg) |
|
1070 |
|
1071 # Create a target group for the wwn |
|
1072 self._stmf_execute('/usr/sbin/stmfadm', 'create-tg', target_group) |
|
1073 |
|
1074 # Enable the target and add it to the 'tg-wwn-xxx' group |
|
1075 self._stmf_execute('/usr/sbin/stmfadm', 'offline-target', |
|
1076 'wwn.%s' % wwn) |
|
1077 self._stmf_execute('/usr/sbin/stmfadm', 'add-tg-member', '-g', |
|
1078 target_group, 'wwn.%s' % wwn) |
|
1079 |
|
1080 # Add a logical unit view entry |
1097 # Add a logical unit view entry |
1081 # TODO(Strony): replace the auto assigned LUN with '-n' option |
1098 self._stmf_execute('/usr/sbin/stmfadm', 'add-view', '-t', |
1082 if luid is not None: |
1099 self.tg, luid) |
1083 self._stmf_execute('/usr/sbin/stmfadm', 'add-view', '-t', |
1100 self._force_lip_wwn() |
1084 target_group, luid) |
|
1085 self._stmf_execute('/usr/sbin/stmfadm', 'online-target', |
|
1086 'wwn.%s' % wwn) |
|
1087 assert self._target_in_tg(wwn, target_group) |
|
1088 |
1101 |
1089 def remove_export(self, context, volume): |
1102 def remove_export(self, context, volume): |
1090 """Remove an export for a volume.""" |
1103 """Remove an export for a volume.""" |
1091 luid = self._get_luid(volume) |
1104 luid = self._get_luid(volume) |
1092 |
1105 |
1093 if luid is not None: |
1106 if luid is not None: |
1094 wwns = self._get_wwns() |
1107 target_group = self.tg |
1095 wwn = wwns[0] |
|
1096 target_wwn = 'wwn.%s' % wwn |
|
1097 target_group = 'tg-wwn-%s' % wwn |
|
1098 view_lun = self._get_view_and_lun(luid) |
1108 view_lun = self._get_view_and_lun(luid) |
1099 if view_lun['view']: |
1109 if view_lun['view']: |
1100 self._stmf_execute('/usr/sbin/stmfadm', 'remove-view', '-l', |
1110 self._stmf_execute('/usr/sbin/stmfadm', 'remove-view', '-l', |
1101 luid, view_lun['view']) |
1111 luid, view_lun['view']) |
1102 |
1112 |
1103 # Remove the target group when only one LU exists. |
1113 # Remove the target group when the LU to be deleted is last one |
|
1114 # exposed by the target group. |
1104 if self._only_lu(luid): |
1115 if self._only_lu(luid): |
1105 if self._check_target(target_wwn, 'Channel') == 'Online': |
|
1106 self._stmf_execute('/usr/sbin/stmfadm', 'offline-target', |
|
1107 target_wwn) |
|
1108 if self._check_tg(target_group): |
1116 if self._check_tg(target_group): |
1109 self._stmf_execute('/usr/sbin/stmfadm', 'delete-tg', |
1117 self._stmf_execute('/usr/sbin/stmfadm', 'delete-tg', |
1110 target_group) |
1118 target_group) |
1111 |
1119 |
1112 # Remove the LU |
1120 # Remove the LU |
1118 :target_discovered: boolean indicating whether discovery was used |
1126 :target_discovered: boolean indicating whether discovery was used |
1119 :target_wwn: the world wide name of the FC port target |
1127 :target_wwn: the world wide name of the FC port target |
1120 :target_lun: the lun assigned to the LU for the view entry |
1128 :target_lun: the lun assigned to the LU for the view entry |
1121 |
1129 |
1122 """ |
1130 """ |
1123 wwns = self._get_wwns() |
|
1124 if not wwns: |
|
1125 msg = (_("Could not determine fibre channel world wide " |
|
1126 "node names.")) |
|
1127 raise exception.VolumeBackendAPIException(data=msg) |
|
1128 |
|
1129 luid = self._get_luid(volume) |
1131 luid = self._get_luid(volume) |
1130 if not luid: |
1132 if not luid: |
1131 msg = (_("Failed to get logic unit for volume '%s'") |
1133 msg = (_("Failed to get logic unit for volume '%s'") |
1132 % volume['name']) |
1134 % volume['name']) |
1133 raise exception.VolumeBackendAPIException(data=msg) |
1135 raise exception.VolumeBackendAPIException(data=msg) |
1134 |
1136 |
1135 properties = {} |
1137 properties = {} |
1136 |
1138 |
1137 properties['target_discovered'] = True |
1139 properties['target_discovered'] = True |
1138 properties['target_wwn'] = wwns |
1140 properties['target_wwn'] = self._get_target_wwns(self.tg) |
1139 view_lun = self._get_view_and_lun(luid) |
1141 view_lun = self._get_view_and_lun(luid) |
1140 if view_lun['lun'] is not None: |
1142 if view_lun['lun'] is not None: |
1141 properties['target_lun'] = view_lun['lun'] |
1143 properties['target_lun'] = view_lun['lun'] |
1142 return properties |
1144 return properties |
1143 |
1145 |