forked from apache/nifi
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
NIFI-14156 Improved Bootstrap Process on Windows with Attach API
- Added Virtual Machine Attach API implementation of ProcessHandleProvider to support Bootstrap commands on Windows
- Loading branch information
1 parent
60a8a43
commit 378d7e9
Showing
3 changed files
with
209 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 127 additions & 0 deletions
127
...n/java/org/apache/nifi/bootstrap/command/process/VirtualMachineProcessHandleProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.nifi.bootstrap.command.process; | ||
|
||
import com.sun.tools.attach.VirtualMachine; | ||
import com.sun.tools.attach.VirtualMachineDescriptor; | ||
import com.sun.tools.attach.spi.AttachProvider; | ||
import org.apache.nifi.bootstrap.configuration.ConfigurationProvider; | ||
import org.apache.nifi.bootstrap.configuration.SystemProperty; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.Path; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Optional; | ||
import java.util.Properties; | ||
|
||
/** | ||
* Virtual Machine implementation of ProcessHandle Provider using the Attach API with System Properties | ||
*/ | ||
public class VirtualMachineProcessHandleProvider implements ProcessHandleProvider { | ||
private static final Logger logger = LoggerFactory.getLogger(VirtualMachineProcessHandleProvider.class); | ||
|
||
private final ConfigurationProvider configurationProvider; | ||
|
||
public VirtualMachineProcessHandleProvider(final ConfigurationProvider configurationProvider) { | ||
this.configurationProvider = Objects.requireNonNull(configurationProvider); | ||
} | ||
|
||
/** | ||
* Find Process Handle for Application based on matching argument for path to application properties | ||
* | ||
* @return Application Process Handle or empty when not found | ||
*/ | ||
@Override | ||
public Optional<ProcessHandle> findApplicationProcessHandle() { | ||
final Path applicationProperties = configurationProvider.getApplicationProperties(); | ||
return findProcessHandle(SystemProperty.APPLICATION_PROPERTIES, applicationProperties); | ||
} | ||
|
||
/** | ||
* Find Process Handle for Bootstrap based on matching argument for path to bootstrap configuration | ||
* | ||
* @return Bootstrap Process Handle or empty when not found | ||
*/ | ||
@Override | ||
public Optional<ProcessHandle> findBootstrapProcessHandle() { | ||
final Path bootstrapConfiguration = configurationProvider.getBootstrapConfiguration(); | ||
return findProcessHandle(SystemProperty.BOOTSTRAP_CONFIGURATION, bootstrapConfiguration); | ||
} | ||
|
||
private Optional<ProcessHandle> findProcessHandle(final SystemProperty systemProperty, final Path configuration) { | ||
final ProcessHandle currentProcessHandle = ProcessHandle.current(); | ||
final String currentProcessId = Long.toString(currentProcessHandle.pid()); | ||
|
||
Optional<ProcessHandle> processHandleFound = Optional.empty(); | ||
|
||
final List<VirtualMachineDescriptor> virtualMachineDescriptors = VirtualMachine.list(); | ||
for (final VirtualMachineDescriptor virtualMachineDescriptor : virtualMachineDescriptors) { | ||
final String virtualMachineId = virtualMachineDescriptor.id(); | ||
if (currentProcessId.equals(virtualMachineId)) { | ||
continue; | ||
} | ||
|
||
processHandleFound = findProcessHandle(virtualMachineDescriptor, systemProperty, configuration); | ||
if (processHandleFound.isPresent()) { | ||
break; | ||
} | ||
} | ||
|
||
return processHandleFound; | ||
} | ||
|
||
private Optional<ProcessHandle> findProcessHandle(final VirtualMachineDescriptor descriptor, final SystemProperty systemProperty, final Path configuration) { | ||
final AttachProvider attachProvider = descriptor.provider(); | ||
final String virtualMachineId = descriptor.id(); | ||
|
||
Optional<ProcessHandle> processHandle = Optional.empty(); | ||
try { | ||
final VirtualMachine virtualMachine = attachProvider.attachVirtualMachine(virtualMachineId); | ||
logger.debug("Attached Virtual Machine [{}]", virtualMachine.id()); | ||
try { | ||
processHandle = findProcessHandle(virtualMachine, systemProperty, configuration); | ||
} finally { | ||
virtualMachine.detach(); | ||
} | ||
} catch (final Exception e) { | ||
logger.debug("Attach Virtual Machine [{}] failed", virtualMachineId, e); | ||
} | ||
|
||
return processHandle; | ||
} | ||
|
||
private Optional<ProcessHandle> findProcessHandle(final VirtualMachine virtualMachine, final SystemProperty systemProperty, final Path configuration) throws IOException { | ||
final Properties systemProperties = virtualMachine.getSystemProperties(); | ||
final String configurationProperty = systemProperties.getProperty(systemProperty.getProperty()); | ||
final String configurationPath = configuration.toString(); | ||
|
||
final Optional<ProcessHandle> processHandle; | ||
|
||
if (configurationPath.equals(configurationProperty)) { | ||
final String virtualMachineId = virtualMachine.id(); | ||
final long processId = Long.parseLong(virtualMachineId); | ||
processHandle = ProcessHandle.of(processId); | ||
} else { | ||
processHandle = Optional.empty(); | ||
} | ||
|
||
return processHandle; | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
...va/org/apache/nifi/bootstrap/command/process/VirtualMachineProcessHandleProviderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.nifi.bootstrap.command.process; | ||
|
||
import org.apache.nifi.bootstrap.configuration.ConfigurationProvider; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.junit.jupiter.api.io.TempDir; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.jupiter.MockitoExtension; | ||
|
||
import java.nio.file.Path; | ||
import java.util.Optional; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
import static org.mockito.Mockito.when; | ||
|
||
@ExtendWith(MockitoExtension.class) | ||
class VirtualMachineProcessHandleProviderTest { | ||
@Mock | ||
private ConfigurationProvider configurationProvider; | ||
|
||
@TempDir | ||
private Path tempDir; | ||
|
||
private VirtualMachineProcessHandleProvider provider; | ||
|
||
@BeforeEach | ||
void setProvider() { | ||
provider = new VirtualMachineProcessHandleProvider(configurationProvider); | ||
} | ||
|
||
@Test | ||
void testFindApplicationProcessHandleEmpty() { | ||
when(configurationProvider.getApplicationProperties()).thenReturn(tempDir); | ||
final Optional<ProcessHandle> applicationProcessHandle = provider.findApplicationProcessHandle(); | ||
|
||
assertTrue(applicationProcessHandle.isEmpty()); | ||
} | ||
|
||
@Test | ||
void testFindBootstrapProcessHandleEmpty() { | ||
when(configurationProvider.getBootstrapConfiguration()).thenReturn(tempDir); | ||
final Optional<ProcessHandle> bootstrapProcessHandle = provider.findBootstrapProcessHandle(); | ||
|
||
assertTrue(bootstrapProcessHandle.isEmpty()); | ||
} | ||
} |