| 1143 | |
| 1144 | |
| 1145 | Future<Nothing> VolumeManagerProcess::_unpublishVolume(const string& volumeId) |
| 1146 | { |
| 1147 | CHECK(volumes.contains(volumeId)); |
| 1148 | VolumeState& volumeState = volumes.at(volumeId).state; |
| 1149 | |
| 1150 | if (volumeState.state() == VolumeState::NODE_READY) { |
| 1151 | CHECK(volumeState.boot_id().empty()); |
| 1152 | |
| 1153 | if (volumeState.pre_provisioned()) { |
| 1154 | // Since this volume was pre-provisioned, it has reached the end of its |
| 1155 | // lifecycle. Remove it now. |
| 1156 | removeVolume(volumeId); |
| 1157 | } |
| 1158 | |
| 1159 | return Nothing(); |
| 1160 | } |
| 1161 | |
| 1162 | if (volumeState.state() != VolumeState::VOL_READY && |
| 1163 | volumeState.state() != VolumeState::NODE_STAGE && |
| 1164 | volumeState.state() != VolumeState::NODE_UNSTAGE) { |
| 1165 | // Retry after transitioning the volume to `VOL_READY` state. |
| 1166 | return __unpublishVolume(volumeId) |
| 1167 | .then(process::defer(self(), &Self::_unpublishVolume, volumeId)); |
| 1168 | } |
| 1169 | |
| 1170 | if (!nodeCapabilities->stageUnstageVolume) { |
| 1171 | if (volumeState.pre_provisioned()) { |
| 1172 | // Since this volume was pre-provisioned, it has reached the end of its |
| 1173 | // lifecycle. Remove it now. |
| 1174 | removeVolume(volumeId); |
| 1175 | } else { |
| 1176 | // Since this is a no-op, no need to checkpoint here. |
| 1177 | volumeState.set_state(VolumeState::NODE_READY); |
| 1178 | volumeState.clear_boot_id(); |
| 1179 | } |
| 1180 | |
| 1181 | return Nothing(); |
| 1182 | } |
| 1183 | |
| 1184 | // A previously failed `NodeStageVolume` call can be recovered through the |
| 1185 | // current `NodeUnstageVolume` call. See: |
| 1186 | // https://github.com/container-storage-interface/spec/blob/v1.1.0/spec.md#nodestagevolume // NOLINT |
| 1187 | if (volumeState.state() == VolumeState::VOL_READY || |
| 1188 | volumeState.state() == VolumeState::NODE_STAGE) { |
| 1189 | volumeState.set_state(VolumeState::NODE_UNSTAGE); |
| 1190 | checkpointVolumeState(volumeId); |
| 1191 | } |
| 1192 | |
| 1193 | const string stagingPath = paths::getMountStagingPath(mountRootDir, volumeId); |
| 1194 | |
| 1195 | CHECK(os::exists(stagingPath)); |
| 1196 | |
| 1197 | LOG(INFO) << "Calling '/csi.v1.Node/NodeUnstageVolume' for volume '" |
| 1198 | << volumeId << "'"; |
| 1199 | |
| 1200 | NodeUnstageVolumeRequest request; |
| 1201 | request.set_volume_id(volumeId); |
| 1202 | request.set_staging_target_path(stagingPath); |