-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #122 from istraka/junit5_pr_wfdeploy
[native clouds] WildFly deploy operation support for Azure
- Loading branch information
Showing
34 changed files
with
1,111 additions
and
68 deletions.
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
118 changes: 118 additions & 0 deletions
118
clouds/clouds-azure/src/main/java/azure/core/AzureArchiveDeployer.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,118 @@ | ||
package azure.core; | ||
|
||
|
||
import azure.core.AzureIdentifiableSunstoneResource.Identification; | ||
import com.azure.resourcemanager.appservice.models.DeployType; | ||
import com.azure.resourcemanager.appservice.models.PublishingProfile; | ||
import com.azure.resourcemanager.appservice.models.WebApp; | ||
import org.apache.commons.net.ftp.FTP; | ||
import org.apache.commons.net.ftp.FTPClient; | ||
import org.junit.jupiter.api.extension.ExtensionContext; | ||
import org.wildfly.extras.creaper.commands.deployments.Deploy; | ||
import org.wildfly.extras.creaper.commands.deployments.Undeploy; | ||
import org.wildfly.extras.creaper.core.CommandFailedException; | ||
import org.wildfly.extras.creaper.core.online.OnlineManagementClient; | ||
import sunstone.core.api.SunstoneArchiveDeployer; | ||
import sunstone.core.exceptions.IllegalArgumentSunstoneException; | ||
import sunstone.core.exceptions.SunstoneException; | ||
import sunstone.core.exceptions.UnsupportedSunstoneOperationException; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.lang.annotation.Annotation; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.StandardCopyOption; | ||
|
||
|
||
/** | ||
* Purpose: handle deploy operation to WildFly. | ||
* | ||
* Heavily uses {@link AzureIdentifiableSunstoneResource} to determine the destination of deploy operation | ||
* | ||
* To retrieve Azure cloud resources, the class relies on {@link AzureIdentifiableSunstoneResource#get(Annotation, AzureSunstoneStore, Class)}. | ||
* | ||
* Undeploy operations are registered in the extension store so that they are closed once the store is closed | ||
*/ | ||
public class AzureArchiveDeployer implements SunstoneArchiveDeployer { | ||
|
||
static void deployToWebApp(Identification resourceIdentification, InputStream is, AzureSunstoneStore store) throws Exception { | ||
Path tempFile = Files.createTempFile("sunstone-war-deployment-", ".war"); | ||
Files.copy(is, tempFile, StandardCopyOption.REPLACE_EXISTING); | ||
WebApp azureWebApp = resourceIdentification.get(store, WebApp.class); | ||
azureWebApp.deployAsync(DeployType.WAR, tempFile.toFile()).block(); | ||
|
||
store.addClosable(() -> undeployFromWebApp(azureWebApp)); | ||
|
||
azureWebApp.restartAsync().block(); | ||
AzureUtils.waitForWebAppDeployment(azureWebApp); | ||
} | ||
|
||
static void undeployFromWebApp(WebApp webApp) { | ||
PublishingProfile profile = webApp.getPublishingProfile(); | ||
FTPClient ftpClient = new FTPClient(); | ||
String[] ftpUrlSegments = profile.ftpUrl().split("/", 2); | ||
String server = ftpUrlSegments[0]; | ||
try { | ||
ftpClient.connect(server); | ||
ftpClient.enterLocalPassiveMode(); | ||
ftpClient.login(profile.ftpUsername(), profile.ftpPassword()); | ||
ftpClient.setFileType(FTP.BINARY_FILE_TYPE); | ||
|
||
FtpUtils.cleanDirectory(ftpClient, "/site/wwwroot/"); | ||
|
||
ftpClient.disconnect(); | ||
|
||
webApp.restartAsync().block(); | ||
AzureUtils.waitForWebAppCleanState(webApp); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} catch (InterruptedException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
static void deployToVmInstance(String deploymentName, Identification resourceIdentification, InputStream is, AzureSunstoneStore store) throws SunstoneException { | ||
try { | ||
OnlineManagementClient client = AzureIdentifiableSunstoneResourceUtils.resolveOnlineManagementClient(resourceIdentification, store); | ||
client.apply(new Deploy.Builder(is, deploymentName, true).build()); | ||
store.addClosable((AutoCloseable) () -> { | ||
client.apply(new Undeploy.Builder(deploymentName).build()); | ||
client.close(); | ||
}); | ||
} catch (CommandFailedException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
@Override | ||
public void deployAndRegisterUndeploy(String deploymentName, Annotation targetAnnotation, InputStream deployment, ExtensionContext ctx) throws SunstoneException { | ||
AzureSunstoneStore store = AzureSunstoneStore.get(ctx); | ||
Identification identification = new Identification(targetAnnotation); | ||
|
||
if (!identification.type.deployToWildFlySupported()) { | ||
throw new UnsupportedSunstoneOperationException("todo"); | ||
} | ||
|
||
switch (identification.type) { | ||
case VM_INSTANCE: | ||
if (deploymentName.isEmpty()) { | ||
throw new IllegalArgumentSunstoneException("Deployment name can not be empty for Azure virtual machine."); | ||
} | ||
deployToVmInstance(deploymentName, identification, deployment, store); | ||
break; | ||
case WEB_APP: | ||
try { | ||
if (!deploymentName.isEmpty()) { | ||
throw new IllegalArgumentSunstoneException("Deployment name must be empty for Azure Web App. It is always ROOT.war and only WAR is supported."); | ||
} | ||
deployToWebApp(identification, deployment, store); | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
break; | ||
default: | ||
throw new UnsupportedSunstoneOperationException("todo"); | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
clouds/clouds-azure/src/main/java/azure/core/AzureArchiveDeployerProvider.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,26 @@ | ||
package azure.core; | ||
|
||
|
||
import azure.core.AzureIdentifiableSunstoneResource.Identification; | ||
import azure.core.identification.AzureArchiveDeploymentAnnotation; | ||
import sunstone.core.AnnotationUtils; | ||
import sunstone.core.api.SunstoneArchiveDeployer; | ||
import sunstone.core.spi.SunstoneArchiveDeployerProvider; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.util.Optional; | ||
|
||
|
||
public class AzureArchiveDeployerProvider implements SunstoneArchiveDeployerProvider { | ||
|
||
@Override | ||
public Optional<SunstoneArchiveDeployer> create(Annotation annotation) { | ||
if (AnnotationUtils.isAnnotatedBy(annotation.annotationType(), AzureArchiveDeploymentAnnotation.class)) { | ||
Identification identification = new Identification(annotation); | ||
if (identification.type != AzureIdentifiableSunstoneResource.UNSUPPORTED && identification.type.deployToWildFlySupported()) { | ||
return Optional.of(new AzureArchiveDeployer()); | ||
} | ||
} | ||
return Optional.empty(); | ||
} | ||
} |
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
49 changes: 49 additions & 0 deletions
49
clouds/clouds-azure/src/main/java/azure/core/AzureIdentifiableSunstoneResourceUtils.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,49 @@ | ||
package azure.core; | ||
|
||
|
||
import azure.core.identification.AzureVirtualMachine; | ||
import com.azure.resourcemanager.appservice.models.WebApp; | ||
import com.azure.resourcemanager.compute.models.VirtualMachine; | ||
import org.wildfly.extras.creaper.core.online.OnlineManagementClient; | ||
import sunstone.api.EapMode; | ||
import sunstone.api.inject.Hostname; | ||
import sunstone.core.CreaperUtils; | ||
import sunstone.core.exceptions.SunstoneException; | ||
import sunstone.core.exceptions.UnsupportedSunstoneOperationException; | ||
|
||
import java.io.IOException; | ||
|
||
import static azure.core.AzureIdentifiableSunstoneResource.VM_INSTANCE; | ||
|
||
public class AzureIdentifiableSunstoneResourceUtils { | ||
|
||
static Hostname resolveHostname(AzureIdentifiableSunstoneResource.Identification identification, AzureSunstoneStore store) throws SunstoneException { | ||
switch (identification.type) { | ||
case VM_INSTANCE: | ||
VirtualMachine vm = identification.get(store, VirtualMachine.class); | ||
return vm.getPrimaryPublicIPAddress()::ipAddress; | ||
case WEB_APP: | ||
WebApp app = identification.get(store, WebApp.class); | ||
return app::defaultHostname; | ||
default: | ||
throw new UnsupportedSunstoneOperationException("Unsupported type for getting hostname: " + identification.type); | ||
} | ||
} | ||
|
||
static OnlineManagementClient resolveOnlineManagementClient(AzureIdentifiableSunstoneResource.Identification identification, AzureSunstoneStore store) throws SunstoneException { | ||
try { | ||
if (identification.type == VM_INSTANCE) { | ||
AzureVirtualMachine annotation = (AzureVirtualMachine) identification.identification; | ||
if (annotation.mode() == EapMode.STANDALONE) { | ||
return CreaperUtils.createStandaloneManagementClient(resolveHostname(identification, store).get(), annotation.standalone()); | ||
} else { | ||
throw new UnsupportedSunstoneOperationException("Only standalone mode is supported for injecting OnlineManagementClient."); | ||
} | ||
} else { | ||
throw new UnsupportedSunstoneOperationException("Only Azure VM instance is supported for injecting OnlineManagementClient."); | ||
} | ||
} catch (IOException e) { | ||
throw new SunstoneException(e); | ||
} | ||
} | ||
} |
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
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
Oops, something went wrong.