22
33import org .apache .commons .lang .StringUtils ;
44import org .springframework .beans .factory .annotation .Autowired ;
5- import org .zstack .compute .vm .VmGlobalConfig ;
65import org .zstack .compute .vm .devices .TpmEncryptedResourceKeyBackend ;
76import org .zstack .compute .vm .devices .TpmEncryptedResourceKeyBackend .CloneEncryptedResourceKeyContext ;
87import org .zstack .core .Platform ;
2120import org .zstack .header .core .workflow .FlowTrigger ;
2221import org .zstack .header .core .workflow .NoRollbackFlow ;
2322import org .zstack .header .errorcode .ErrorCode ;
23+ import org .zstack .header .core .NoErrorCompletion ;
2424import org .zstack .header .host .HostConstant ;
2525import org .zstack .header .message .MessageReply ;
2626import org .zstack .header .keyprovider .EncryptedResourceKeyManager ;
2727import org .zstack .header .keyprovider .EncryptedResourceKeyManager .GetOrCreateResourceKeyContext ;
2828import org .zstack .header .keyprovider .EncryptedResourceKeyManager .ResourceKeyResult ;
29+ import org .zstack .header .secret .SecretHostDeleteMsg ;
2930import org .zstack .header .secret .SecretHostDefineMsg ;
3031import org .zstack .header .storage .snapshot .group .VolumeSnapshotGroupVO ;
3132import org .zstack .header .storage .snapshot .group .VolumeSnapshotGroupVO_ ;
3536import org .zstack .header .tpm .entity .TpmSpec ;
3637import org .zstack .header .tpm .entity .TpmVO ;
3738import org .zstack .header .tpm .entity .TpmVO_ ;
39+ import org .zstack .header .vm .HaStartVmInstanceMsg ;
3840import org .zstack .header .vm .PreVmInstantiateResourceExtensionPoint ;
41+ import org .zstack .header .vm .VmAfterExpungeExtensionPoint ;
42+ import org .zstack .header .vm .VmInstanceInventory ;
43+ import org .zstack .header .vm .VmInstanceMigrateExtensionPoint ;
3944import org .zstack .header .vm .VmInstanceSpec ;
4045import org .zstack .header .vm .VmInstantiateResourceException ;
4146import org .zstack .header .vm .additions .VmHostBackupFileVO ;
4247import org .zstack .header .vm .additions .VmHostBackupFileVO_ ;
48+ import org .zstack .header .vm .VmInstanceVO ;
49+ import org .zstack .header .vm .VmInstanceVO_ ;
4350import org .zstack .header .vm .additions .VmHostFileType ;
4451import org .zstack .header .vm .additions .VmHostFileVO ;
4552import org .zstack .header .vm .additions .VmHostFileVO_ ;
6067import static org .zstack .core .Platform .operr ;
6168
6269public class KvmTpmExtensions implements KVMStartVmExtensionPoint ,
63- PreVmInstantiateResourceExtensionPoint {
70+ PreVmInstantiateResourceExtensionPoint ,
71+ VmInstanceMigrateExtensionPoint ,
72+ VmAfterExpungeExtensionPoint {
6473 private static final CLogger logger = Utils .getLogger (KvmTpmExtensions .class );
6574
6675 @ Autowired
@@ -122,6 +131,16 @@ public void beforeStartVmOnKvm(KVMHostInventory host, VmInstanceSpec spec, KVMAg
122131
123132 @ Override
124133 public void startVmOnKvmSuccess (KVMHostInventory host , VmInstanceSpec spec ) {
134+ if (spec .getMessage () instanceof HaStartVmInstanceMsg ) {
135+ String vmUuid = spec .getVmInventory () == null ? null : spec .getVmInventory ().getUuid ();
136+ String srcHostUuid = spec .getVmInventory () == null ? null : spec .getVmInventory ().getLastHostUuid ();
137+ Integer keyVersion = findTpmKeyVersionByVmUuid (vmUuid );
138+ boolean vmIsOnDestHost = isVmCurrentlyOnExpectedHost (vmUuid , host .getUuid ());
139+ if (vmIsOnDestHost && StringUtils .isNotBlank (srcHostUuid ) && !host .getUuid ().equals (srcHostUuid )) {
140+ deleteHostSecretBestEffort (srcHostUuid , vmUuid , keyVersion ,
141+ "ha-start-success" );
142+ }
143+ }
125144 clearRollbackInfo (spec );
126145 }
127146
@@ -229,10 +248,11 @@ public void rollback(FlowRollback trigger, Map data) {
229248
230249 @ Override
231250 public boolean skip (Map data ) {
232- boolean shouldSkip = VmGlobalConfig .ALLOWED_TPM_VM_WITHOUT_KMS .value (Boolean .class )
233- && StringUtils .isBlank (context .providerUuid );
251+ boolean shouldSkip = StringUtils .isBlank (context .providerUuid );
234252 if (shouldSkip ) {
235- logger .info ("skip create-dek: allowed.tpm.vm.without.kms is enabled and no KMS provider bound" );
253+ logger .info (String .format (
254+ "skip ensure-resource-key-ref for tpm[uuid:%s] due to missing key provider binding, try host secret first" ,
255+ context .tpmUuid ));
236256 }
237257 return shouldSkip ;
238258 }
@@ -253,7 +273,6 @@ public void run(FlowTrigger trigger, Map data) {
253273 keyCtx .setResourceUuid (context .tpmUuid );
254274 keyCtx .setResourceType (TpmVO .class .getSimpleName ());
255275 keyCtx .setKeyProviderUuid (context .providerUuid );
256- keyCtx .setKeyProviderName (context .providerName );
257276 keyCtx .setPurpose ("vtpm" );
258277
259278 resourceKeyManager .getOrCreateKey (keyCtx , new ReturnValueCompletion <ResourceKeyResult >(trigger ) {
@@ -488,4 +507,91 @@ private String findSourceTpmUuidFromSnapshotTpmBackupFile(String tpmBackupFileUu
488507 .select (TpmVO_ .uuid )
489508 .findValue ();
490509 }
510+
511+ @ Override
512+ public void afterMigrateVm (VmInstanceInventory inv , String srcHostUuid , NoErrorCompletion completion ) {
513+ String vmUuid = inv == null ? null : inv .getUuid ();
514+ String destHostUuid = inv == null ? null : inv .getHostUuid ();
515+ if (StringUtils .isBlank (vmUuid ) || StringUtils .isBlank (srcHostUuid ) || srcHostUuid .equals (destHostUuid )) {
516+ completion .done ();
517+ return ;
518+ }
519+
520+ if (!isVmCurrentlyOnExpectedHost (vmUuid , destHostUuid )) {
521+ completion .done ();
522+ return ;
523+ }
524+
525+ Integer keyVersion = findTpmKeyVersionByVmUuid (vmUuid );
526+ deleteHostSecretBestEffort (srcHostUuid , vmUuid , keyVersion , "after-migrate" );
527+ completion .done ();
528+ }
529+
530+ @ Override
531+ public void vmAfterExpunge (VmInstanceInventory vm ) {
532+ String vmUuid = vm .getUuid ();
533+ Integer keyVersion = findTpmKeyVersionByVmUuid (vmUuid );
534+
535+ java .util .Set <String > hostUuids = new java .util .HashSet <>();
536+ if (StringUtils .isNotBlank (vm .getHostUuid ())) {
537+ hostUuids .add (vm .getHostUuid ());
538+ }
539+ if (StringUtils .isNotBlank (vm .getLastHostUuid ())) {
540+ hostUuids .add (vm .getLastHostUuid ());
541+ }
542+
543+ if (hostUuids .isEmpty ()) {
544+ return ;
545+ }
546+
547+ for (String hostUuid : hostUuids ) {
548+ deleteHostSecretBestEffort (hostUuid , vmUuid , keyVersion , "expunge" );
549+ }
550+ }
551+
552+ private Integer findTpmKeyVersionByVmUuid (String vmUuid ) {
553+ if (StringUtils .isBlank (vmUuid )) {
554+ return null ;
555+ }
556+ String tpmUuid = Q .New (TpmVO .class )
557+ .eq (TpmVO_ .vmInstanceUuid , vmUuid )
558+ .select (TpmVO_ .uuid )
559+ .findValue ();
560+ return tpmUuid == null ? null : resourceKeyBackend .findKeyVersionByTpm (tpmUuid );
561+ }
562+
563+ private boolean isVmCurrentlyOnExpectedHost (String vmUuid , String expectedHostUuid ) {
564+ if (StringUtils .isBlank (vmUuid ) || StringUtils .isBlank (expectedHostUuid )) {
565+ return false ;
566+ }
567+
568+ String currentHostUuid = Q .New (VmInstanceVO .class )
569+ .select (VmInstanceVO_ .hostUuid )
570+ .eq (VmInstanceVO_ .uuid , vmUuid )
571+ .findValue ();
572+ return expectedHostUuid .equals (currentHostUuid );
573+ }
574+
575+ private void deleteHostSecretBestEffort (String hostUuid , String vmUuid , Integer keyVersion , String reason ) {
576+ if (StringUtils .isBlank (hostUuid ) || StringUtils .isBlank (vmUuid )) {
577+ return ;
578+ }
579+
580+ SecretHostDeleteMsg dmsg = new SecretHostDeleteMsg ();
581+ dmsg .setHostUuid (hostUuid );
582+ dmsg .setVmUuid (vmUuid );
583+ dmsg .setPurpose ("vtpm" );
584+ dmsg .setKeyVersion (keyVersion );
585+ bus .makeTargetServiceIdByResourceUuid (dmsg , HostConstant .SERVICE_ID , hostUuid );
586+ bus .send (dmsg , new CloudBusCallBack (null ) {
587+ @ Override
588+ public void run (MessageReply reply ) {
589+ if (!reply .isSuccess ()) {
590+ logger .warn (String .format (
591+ "best-effort delete host secret failed on %s for vm[uuid:%s], host[uuid:%s]: %s" ,
592+ reason , vmUuid , hostUuid , reply .getError ().getDetails ()));
593+ }
594+ }
595+ });
596+ }
491597}
0 commit comments