|
12 | 12 | import org.zstack.compute.cluster.arch.ClusterResourceConfigInitializer; |
13 | 13 | import org.zstack.compute.host.*; |
14 | 14 | import org.zstack.compute.vm.*; |
| 15 | +import org.zstack.compute.vm.devices.TpmEncryptedResourceKeyBackend; |
| 16 | +import org.zstack.compute.vm.devices.VmTpmManager; |
15 | 17 | import org.zstack.core.asyncbatch.While; |
16 | 18 | import org.zstack.core.cloudbus.ResourceDestinationMaker; |
17 | 19 | import org.zstack.core.timeout.TimeHelper; |
|
55 | 57 | import org.zstack.header.exception.CloudRuntimeException; |
56 | 58 | import org.zstack.header.host.*; |
57 | 59 | import org.zstack.header.host.MigrateVmOnHypervisorMsg.StorageMigrationPolicy; |
| 60 | +import org.zstack.header.keyprovider.EncryptedResourceKeyManager; |
| 61 | +import org.zstack.header.keyprovider.EncryptedResourceKeyManager.GetOrCreateResourceKeyContext; |
| 62 | +import org.zstack.header.keyprovider.EncryptedResourceKeyManager.ResourceKeyResult; |
58 | 63 | import org.zstack.header.secret.SecretHostDefineMsg; |
59 | 64 | import org.zstack.header.secret.SecretHostDefineReply; |
60 | 65 | import org.zstack.header.message.APIMessage; |
|
68 | 73 | import org.zstack.header.rest.RESTFacade; |
69 | 74 | import org.zstack.header.storage.primary.*; |
70 | 75 | import org.zstack.header.tag.SystemTagInventory; |
| 76 | +import org.zstack.header.tpm.entity.TpmVO; |
71 | 77 | import org.zstack.header.vm.*; |
72 | 78 | import org.zstack.header.vm.devices.DeviceAddress; |
73 | 79 | import org.zstack.header.volume.*; |
@@ -164,6 +170,10 @@ public class KVMHost extends HostBase implements Host { |
164 | 170 | private AccountManager accountMgr; |
165 | 171 | @Autowired |
166 | 172 | private ResourceDestinationMaker destMaker; |
| 173 | + @Autowired |
| 174 | + private TpmEncryptedResourceKeyBackend tpmKeyBackend; |
| 175 | + @Autowired |
| 176 | + private EncryptedResourceKeyManager resourceKeyManager; |
167 | 177 |
|
168 | 178 | private KVMHostContext context; |
169 | 179 |
|
@@ -3162,6 +3172,146 @@ public void fail(ErrorCode errorCode) { |
3162 | 3172 | } |
3163 | 3173 | }); |
3164 | 3174 |
|
| 3175 | + flow(new NoRollbackFlow() { |
| 3176 | + String __name__ = "ensure-secret-on-dst-before-migrate"; |
| 3177 | + |
| 3178 | + @Override |
| 3179 | + public void run(FlowTrigger trigger, Map data) { |
| 3180 | + String tpmUuid = VmTpmManager.findTpmUuidForVmOrNull(vmUuid); |
| 3181 | + if (StringUtils.isBlank(tpmUuid)) { |
| 3182 | + trigger.next(); |
| 3183 | + return; |
| 3184 | + } |
| 3185 | + String providerUuid = tpmKeyBackend.findKeyProviderUuidByTpm(tpmUuid); |
| 3186 | + String providerName = tpmKeyBackend.findKeyProviderNameByTpm(tpmUuid); |
| 3187 | + if (StringUtils.isBlank(providerUuid) && StringUtils.isBlank(providerName)) { |
| 3188 | + trigger.fail(operr("missing TPM resource key binding for tpm[uuid:%s] before migrate", tpmUuid)); |
| 3189 | + return; |
| 3190 | + } |
| 3191 | + |
| 3192 | + GetOrCreateResourceKeyContext keyCtx = new GetOrCreateResourceKeyContext(); |
| 3193 | + keyCtx.setResourceUuid(tpmUuid); |
| 3194 | + keyCtx.setResourceType(TpmVO.class.getSimpleName()); |
| 3195 | + keyCtx.setKeyProviderUuid(providerUuid); |
| 3196 | + keyCtx.setKeyProviderName(providerName); |
| 3197 | + keyCtx.setPurpose("vtpm"); |
| 3198 | + resourceKeyManager.getOrCreateKey(keyCtx, new ReturnValueCompletion<ResourceKeyResult>(trigger) { |
| 3199 | + @Override |
| 3200 | + public void success(ResourceKeyResult result) { |
| 3201 | + String effectiveProviderName = result.getKeyProviderName(); |
| 3202 | + if (StringUtils.isBlank(effectiveProviderName)) { |
| 3203 | + effectiveProviderName = providerName; |
| 3204 | + } |
| 3205 | + if (StringUtils.isBlank(effectiveProviderName)) { |
| 3206 | + trigger.fail(operr("missing effective key provider name for tpm[uuid:%s] before migrate", tpmUuid)); |
| 3207 | + return; |
| 3208 | + } |
| 3209 | + |
| 3210 | + final String usageInstance = "tpm0"; |
| 3211 | + final Integer[] keyVersionHolder = new Integer[1]; |
| 3212 | + final String[] sourceSecretUuidHolder = new String[1]; |
| 3213 | + |
| 3214 | + FlowChain chain = FlowChainBuilder.newSimpleFlowChain(); |
| 3215 | + chain.setName(String.format("get-and-ensure-vtpm-secret-vm-%s", vmUuid)); |
| 3216 | + chain.then(new NoRollbackFlow() { |
| 3217 | + String __name__ = "get-source-secret-uuid"; |
| 3218 | + |
| 3219 | + @Override |
| 3220 | + public void run(FlowTrigger innerTrigger, Map data) { |
| 3221 | + Object keyVersionObj = SQL.New("select keyVersion from EncryptedResourceKeyRefVO " + |
| 3222 | + "where resourceType = :resourceType and resourceUuid = :resourceUuid") |
| 3223 | + .param("resourceType", TpmVO.class.getSimpleName()) |
| 3224 | + .param("resourceUuid", tpmUuid) |
| 3225 | + .find(); |
| 3226 | + if (keyVersionObj == null) { |
| 3227 | + innerTrigger.fail(operr("cannot find keyVersion in EncryptedResourceKeyRefVO for tpm[uuid:%s] before migrate", tpmUuid)); |
| 3228 | + return; |
| 3229 | + } |
| 3230 | + if (!(keyVersionObj instanceof Number)) { |
| 3231 | + innerTrigger.fail(operr("invalid keyVersion type[%s] in EncryptedResourceKeyRefVO for tpm[uuid:%s] before migrate", |
| 3232 | + keyVersionObj.getClass().getName(), tpmUuid)); |
| 3233 | + return; |
| 3234 | + } |
| 3235 | + |
| 3236 | + keyVersionHolder[0] = ((Number) keyVersionObj).intValue(); |
| 3237 | + KVMAgentCommands.SecretHostGetCmd getCmd = new KVMAgentCommands.SecretHostGetCmd(); |
| 3238 | + getCmd.setVmUuid(vmUuid); |
| 3239 | + getCmd.setPurpose("vtpm"); |
| 3240 | + getCmd.setKeyVersion(0); |
| 3241 | + getCmd.setUsageInstance(usageInstance); |
| 3242 | + restf.asyncJsonPost(buildUrl(KVMConstant.KVM_GET_SECRET_PATH), getCmd, |
| 3243 | + new JsonAsyncRESTCallback<KVMAgentCommands.SecretHostGetResponse>(innerTrigger) { |
| 3244 | + @Override |
| 3245 | + public void fail(ErrorCode err) { |
| 3246 | + innerTrigger.fail(err != null ? err : operr("get secret on source host failed before migrate")); |
| 3247 | + } |
| 3248 | + |
| 3249 | + @Override |
| 3250 | + public void success(KVMAgentCommands.SecretHostGetResponse getRsp) { |
| 3251 | + if (getRsp == null || !getRsp.isSuccess() || StringUtils.isBlank(getRsp.getSecretUuid())) { |
| 3252 | + String details = getRsp == null ? "empty response" : getRsp.getError(); |
| 3253 | + innerTrigger.fail(operr("failed to get source secret uuid before migrate: %s", details)); |
| 3254 | + return; |
| 3255 | + } |
| 3256 | + |
| 3257 | + sourceSecretUuidHolder[0] = getRsp.getSecretUuid(); |
| 3258 | + innerTrigger.next(); |
| 3259 | + } |
| 3260 | + |
| 3261 | + @Override |
| 3262 | + public Class<KVMAgentCommands.SecretHostGetResponse> getReturnClass() { |
| 3263 | + return KVMAgentCommands.SecretHostGetResponse.class; |
| 3264 | + } |
| 3265 | + }, TimeUnit.SECONDS, KVMConstant.ENVELOPE_KEY_HTTP_TIMEOUT_SEC); |
| 3266 | + } |
| 3267 | + }).then(new NoRollbackFlow() { |
| 3268 | + String __name__ = "ensure-secret-on-dst"; |
| 3269 | + |
| 3270 | + @Override |
| 3271 | + public void run(FlowTrigger innerTrigger, Map data) { |
| 3272 | + SecretHostDefineMsg innerMsg = new SecretHostDefineMsg(); |
| 3273 | + innerMsg.setHostUuid(dstHostUuid); |
| 3274 | + innerMsg.setVmUuid(vmUuid); |
| 3275 | + innerMsg.setDekBase64(result.getDekBase64()); |
| 3276 | + innerMsg.setPurpose("vtpm"); |
| 3277 | + innerMsg.setKeyVersion(0); |
| 3278 | + innerMsg.setUsageInstance(usageInstance); |
| 3279 | + innerMsg.setSecretUuid(sourceSecretUuidHolder[0]); |
| 3280 | + innerMsg.setDescription(String.format("Define secret for VM %s before live migration", vmUuid)); |
| 3281 | + bus.makeTargetServiceIdByResourceUuid(innerMsg, HostConstant.SERVICE_ID, innerMsg.getHostUuid()); |
| 3282 | + bus.send(innerMsg, new CloudBusCallBack(innerTrigger) { |
| 3283 | + @Override |
| 3284 | + public void run(MessageReply reply) { |
| 3285 | + if (reply.isSuccess()) { |
| 3286 | + innerTrigger.next(); |
| 3287 | + } else { |
| 3288 | + innerTrigger.fail(reply.getError()); |
| 3289 | + } |
| 3290 | + } |
| 3291 | + }); |
| 3292 | + } |
| 3293 | + }).error(new FlowErrorHandler(trigger) { |
| 3294 | + @Override |
| 3295 | + public void handle(ErrorCode errCode, Map data) { |
| 3296 | + trigger.fail(errCode); |
| 3297 | + } |
| 3298 | + }).done(new FlowDoneHandler(trigger) { |
| 3299 | + @Override |
| 3300 | + public void handle(Map data) { |
| 3301 | + trigger.next(); |
| 3302 | + } |
| 3303 | + }).start(); |
| 3304 | + } |
| 3305 | + |
| 3306 | + @Override |
| 3307 | + public void fail(ErrorCode errorCode) { |
| 3308 | + trigger.fail(errorCode); |
| 3309 | + } |
| 3310 | + }); |
| 3311 | + } |
| 3312 | + |
| 3313 | + }); |
| 3314 | + |
3165 | 3315 | flow(new NoRollbackFlow() { |
3166 | 3316 | String __name__ = "migrate-vm"; |
3167 | 3317 |
|
@@ -5317,8 +5467,9 @@ private void handle(SecretHostDefineMsg msg) { |
5317 | 5467 | bus.reply(msg, reply); |
5318 | 5468 | return; |
5319 | 5469 | } |
5320 | | - if (StringUtils.isBlank(msg.getVmUuid()) || StringUtils.isBlank(msg.getPurpose()) || StringUtils.isBlank(msg.getProviderName())) { |
5321 | | - reply.setError(operr("vmUuid, purpose and providerName are required for ensure secret")); |
| 5470 | + if (StringUtils.isBlank(msg.getVmUuid()) || StringUtils.isBlank(msg.getPurpose()) |
| 5471 | + || msg.getKeyVersion() == null || StringUtils.isBlank(msg.getUsageInstance())) { |
| 5472 | + reply.setError(operr("vmUuid, purpose, keyVersion and usageInstance are required for ensure secret")); |
5322 | 5473 | bus.reply(msg, reply); |
5323 | 5474 | return; |
5324 | 5475 | } |
@@ -5396,7 +5547,9 @@ private void handle(SecretHostDefineMsg msg) { |
5396 | 5547 | cmd.setEncryptedDek(envelopeDekBase64); |
5397 | 5548 | cmd.setVmUuid(msg.getVmUuid()); |
5398 | 5549 | cmd.setPurpose(msg.getPurpose()); |
5399 | | - cmd.setProviderName(msg.getProviderName()); |
| 5550 | + cmd.setKeyVersion(msg.getKeyVersion()); |
| 5551 | + cmd.setUsageInstance(msg.getUsageInstance()); |
| 5552 | + cmd.setSecretUuid(msg.getSecretUuid()); |
5400 | 5553 | cmd.setDescription(msg.getDescription() != null ? msg.getDescription() : ""); |
5401 | 5554 | restf.asyncJsonPost(url, cmd, new JsonAsyncRESTCallback<KVMAgentCommands.SecretHostDefineResponse>(msg, reply) { |
5402 | 5555 | @Override |
|
0 commit comments