Search in sources :

Example 1 with PlatformSeparators

use of com.oracle.bedrock.runtime.options.PlatformSeparators in project oracle-bedrock by coherence-community.

the class AbstractRemoteApplicationLauncher method launch.

@Override
public A launch(Platform platform, MetaClass<A> metaClass, OptionsByType optionsByType) {
    // establish the diagnostics output table
    Table diagnosticsTable = new Table();
    diagnosticsTable.getOptions().add(Table.orderByColumn(0));
    if (platform != null) {
        diagnosticsTable.addRow("Target Platform", platform.getName());
    }
    // ----- establish the launch Options for the Application -----
    // add the platform options
    OptionsByType launchOptions = OptionsByType.of(platform.getOptions()).addAll(optionsByType);
    // add the meta-class options
    metaClass.onLaunching(platform, launchOptions);
    // ---- establish the default Options ----
    // define the PlatformSeparators as Unix if they are not already defined
    launchOptions.addIfAbsent(PlatformSeparators.forUnix());
    // define the default Platform Shell (assume BASH)
    launchOptions.addIfAbsent(Shell.is(Shell.Type.BASH));
    // define the "local.address" variable so that is can be used for resolving this platform address
    launchOptions.add(Variable.with("local.address", LocalPlatform.get().getAddress().getHostAddress()));
    // ----- establish an identity for the application -----
    // add a unique runtime id for expression support
    launchOptions.add(Variable.with("bedrock.runtime.id", UUID.randomUUID()));
    // ----- establish default Profiles for this Platform (and Builder) -----
    // auto-detect and add externally defined profiles
    launchOptions.addAll(Profiles.getProfiles());
    for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
        profile.onLaunching(platform, metaClass, launchOptions);
    }
    // ----- add the diagnostic table to the options so it can be used by the terminal -----
    launchOptions.add(diagnosticsTable);
    // ----- prior to launching the application, let the implementation enhance the launch options -----
    onLaunching(launchOptions);
    // ----- give the MetaClass a last chance to manipulate any options -----
    metaClass.onLaunch(platform, launchOptions);
    // ----- determine the display name for the application -----
    DisplayName displayName = getDisplayName(launchOptions);
    // determine the Executable
    Executable executable = launchOptions.get(Executable.class);
    // ----- deploy remote application artifacts -----
    // determine the DeploymentArtifacts based on those specified by the Deployment option
    ArrayList<DeploymentArtifact> artifactsToDeploy = new ArrayList<>();
    Deployment deployment = launchOptions.get(Deployment.class);
    if (deployment != null) {
        try {
            artifactsToDeploy.addAll(deployment.getDeploymentArtifacts(platform, launchOptions));
        } catch (Exception e) {
            throw new RuntimeException("Failed to determine artifacts to deploy", e);
        }
    }
    // determine the separators for the platform
    PlatformSeparators separators = launchOptions.get(PlatformSeparators.class);
    // assume the remote directory is the working directory
    WorkingDirectory workingDirectory = launchOptions.getOrSetDefault(WorkingDirectory.class, WorkingDirectory.temporaryDirectory());
    File remoteDirectoryFile = workingDirectory.resolve(platform, launchOptions);
    if (remoteDirectoryFile == null) {
        remoteDirectoryFile = WorkingDirectory.temporaryDirectory().resolve(platform, launchOptions);
    }
    String remoteDirectory = separators.asPlatformFileName(remoteDirectoryFile.toString());
    // Set the resolved working directory back into the options
    launchOptions.add(WorkingDirectory.at(remoteDirectoryFile));
    if (remoteDirectoryFile != null) {
        diagnosticsTable.addRow("Working Directory", remoteDirectoryFile.toString());
    }
    // Obtain the RemoteShell that will be used to launch the process
    RemoteTerminalBuilder terminalBuilder = launchOptions.getOrSetDefault(RemoteTerminalBuilder.class, RemoteTerminals.ssh());
    RemoteTerminal terminal = terminalBuilder.build(platform);
    // create the working directory
    terminal.makeDirectories(remoteDirectory, launchOptions);
    // deploy any artifacts required
    Deployer deployer = launchOptions.getOrSetDefault(Deployer.class, new SftpDeployer());
    DeployedArtifacts deployedArtifacts = deployer.deploy(artifactsToDeploy, remoteDirectory, platform, launchOptions.asArray());
    // add the remote directory as something to clean up
    deployedArtifacts.add(remoteDirectoryFile);
    if (!deployedArtifacts.isEmpty()) {
        // when we've deployed artifacts we need to add a listener to clean them up
        launchOptions.add(Decoration.of(new ApplicationListener<A>() {

            @Override
            public void onClosing(A application, OptionsByType optionsByType) {
            // nothing to do on closing
            }

            @Override
            public void onClosed(A application, OptionsByType optionsByType) {
                Level logLevel = optionsByType.get(LaunchLogging.class).isEnabled() ? Level.INFO : Level.OFF;
                try (DiagnosticsRecording diagnostics = DiagnosticsRecording.create("Undeploy Diagnostics for " + application.getName() + " on platform " + platform.getName()).using(LOGGER, logLevel)) {
                    diagnostics.add("Platform", "Resource");
                    try (DiagnosticsRecording local = DiagnosticsRecording.section("Local Platform")) {
                        // clean up the locally created temporary artifacts
                        artifactsToDeploy.stream().filter(DeploymentArtifact::isTemporary).forEach(artifact -> {
                            try {
                                // attempt to remove the local file
                                artifact.getSourceFile().delete();
                                // include diagnostics
                                local.add(artifact.getSourceFile().toString());
                            } catch (Exception e) {
                                // log exceptions when attempting to remove local sources
                                LOGGER.log(Level.WARNING, "Failed to remove temporary " + artifact.toString() + " for application " + application.getName(), e);
                                // include diagnostics
                                local.add(artifact.getSourceFile() + " (failed to undeploy)");
                            }
                        });
                    }
                    // undeploy the deployed artifacts
                    deployer.undeploy(deployedArtifacts, platform, launchOptions.asArray());
                }
            }

            @Override
            public void onLaunched(A application) {
            // nothing to do after launching
            }
        }));
    }
    // Realize the application arguments
    Arguments arguments = launchOptions.get(Arguments.class);
    List<String> argList = arguments.resolve(platform, launchOptions);
    // Set the actual arguments used back into the options
    launchOptions.add(Arguments.of(argList));
    // TODO: put a try/catch around the terminal.launch here so we can clean up the RemoteExecutor if
    // the application failed to launch
    // determine the application class that will represent the running application
    Class<? extends A> applicationClass = metaClass.getImplementationClass(platform, launchOptions);
    diagnosticsTable.addRow("Application", displayName.resolve(launchOptions));
    if (argList.size() > 0) {
        diagnosticsTable.addRow("Application Arguments ", argList.stream().collect(Collectors.joining(" ")));
    }
    diagnosticsTable.addRow("Application Launch Time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    // ----- start the process and establish the application -----
    // launch the remote process
    RemoteApplicationProcess remoteProcess = terminal.launch(this, applicationClass, launchOptions);
    // adapt the remote process into something that the application can use
    ApplicationProcess process = adapt(remoteProcess);
    // create the Application based on the RemoteApplicationProcess
    A application;
    try {
        // attempt to find a constructor(Platform, JavaApplicationProcess, Options)
        Constructor<? extends A> constructor = ReflectionHelper.getCompatibleConstructor(applicationClass, platform.getClass(), process.getClass(), OptionsByType.class);
        // create the application
        application = constructor.newInstance(platform, process, launchOptions);
    } catch (Exception e) {
        throw new RuntimeException("Failed to instantiate the Application class specified by the MetaClass:" + metaClass, e);
    }
    // ----- after launching the application, let the implementation interact with the application -----
    onLaunched(application, launchOptions);
    // ----- notify the MetaClass that the application has been launched -----
    metaClass.onLaunched(platform, application, launchOptions);
    for (Profile profile : launchOptions.getInstancesOf(Profile.class)) {
        profile.onLaunched(platform, application, launchOptions);
    }
    // notify the ApplicationListener-based Options that the application has been launched
    for (ApplicationListener listener : launchOptions.getInstancesOf(ApplicationListener.class)) {
        listener.onLaunched(application);
    }
    return application;
}
Also used : DiagnosticsRecording(com.oracle.bedrock.diagnostics.DiagnosticsRecording) ArrayList(java.util.ArrayList) Deployment(com.oracle.bedrock.runtime.remote.options.Deployment) Profile(com.oracle.bedrock.runtime.Profile) DisplayName(com.oracle.bedrock.runtime.options.DisplayName) Executable(com.oracle.bedrock.runtime.options.Executable) Deployer(com.oracle.bedrock.runtime.remote.options.Deployer) SftpDeployer(com.oracle.bedrock.runtime.remote.ssh.SftpDeployer) PlatformSeparators(com.oracle.bedrock.runtime.options.PlatformSeparators) WorkingDirectory(com.oracle.bedrock.runtime.options.WorkingDirectory) Table(com.oracle.bedrock.table.Table) Arguments(com.oracle.bedrock.runtime.options.Arguments) Date(java.util.Date) ApplicationListener(com.oracle.bedrock.runtime.ApplicationListener) SftpDeployer(com.oracle.bedrock.runtime.remote.ssh.SftpDeployer) Level(java.util.logging.Level) ApplicationProcess(com.oracle.bedrock.runtime.ApplicationProcess) OptionsByType(com.oracle.bedrock.OptionsByType) File(java.io.File) SimpleDateFormat(java.text.SimpleDateFormat)

Example 2 with PlatformSeparators

use of com.oracle.bedrock.runtime.options.PlatformSeparators in project oracle-bedrock by coherence-community.

the class SftpDeployer method deploy.

@Override
public DeployedArtifacts deploy(List<DeploymentArtifact> artifactsToDeploy, String remoteDirectory, Platform platform, Option... deploymentOptions) {
    DeployedArtifacts deployedArtifacts = new DeployedArtifacts();
    if (artifactsToDeploy == null || artifactsToDeploy.isEmpty()) {
        return deployedArtifacts;
    }
    if (!(platform instanceof RemotePlatform)) {
        throw new IllegalArgumentException("The platform parameter must be an instance of RemotePlatform");
    }
    Table deploymentTable = new Table();
    JSchSocketFactory socketFactory = new JSchSocketFactory();
    RemotePlatform remotePlatform = (RemotePlatform) platform;
    String userName = remotePlatform.getUserName();
    Authentication authentication = remotePlatform.getAuthentication();
    String hostName = remotePlatform.getAddress().getHostName();
    int port = remotePlatform.getPort();
    // Create the deployment options
    OptionsByType optionsByType = OptionsByType.empty();
    // Add the Platform options
    optionsByType.addAll(platform.getOptions());
    // Override with specified Options
    optionsByType.addAll(deploymentOptions);
    // initially there's no session
    Session session = null;
    try {
        // Obtain the connected JSch Session
        session = sessionFactory.createSession(hostName, port, userName, authentication, socketFactory, optionsByType);
        // ----- deploy remote application artifacts (using sftp) -----
        // determine the separators for the platform
        PlatformSeparators separators = optionsByType.get(PlatformSeparators.class);
        if (artifactsToDeploy.size() > 0) {
            ChannelSftp sftpChannel = null;
            try {
                // open an sftp channel that we can use to copy over the artifacts
                sftpChannel = (ChannelSftp) session.openChannel("sftp");
                sftpChannel.connect(session.getTimeout());
                try {
                    // Obtain the status of the remote directory
                    sftpChannel.lstat(remoteDirectory);
                } catch (SftpException _ignored) {
                    // the remote directory does not exist so attempt to create it
                    sftpChannel.mkdir(remoteDirectory);
                    // add the directory as something to clean up
                    deployedArtifacts.add(new File(remoteDirectory));
                }
                // copy deployment artifacts into the remote server
                for (DeploymentArtifact artifactToDeploy : artifactsToDeploy) {
                    // acquire the source file to deploy
                    File sourceFile = artifactToDeploy.getSourceFile();
                    // change to the desired remote directory
                    File destinationFile = artifactToDeploy.getDestinationFile();
                    String destinationFileName;
                    if (destinationFile == null) {
                        sftpChannel.cd(remoteDirectory);
                        destinationFileName = sourceFile.getName();
                        // add the file as a deployed artifact
                        deployedArtifacts.add(new File(remoteDirectory, destinationFileName));
                    } else {
                        String destinationFilePath = separators.asPlatformFileName(destinationFile.getParent());
                        String dirName;
                        if (destinationFilePath == null) {
                            dirName = separators.asPlatformFileName(remoteDirectory);
                        } else {
                            dirName = separators.asPlatformFileName(destinationFilePath);
                        }
                        sftpChannel.cd(dirName);
                        destinationFileName = destinationFile.getName();
                        // add the file as a deployed artifact
                        deployedArtifacts.add(new File(dirName, destinationFileName));
                    }
                    // copy the source artifact to the destination file
                    double start = System.currentTimeMillis();
                    sftpChannel.put(new FileInputStream(sourceFile), destinationFileName);
                    double time = (System.currentTimeMillis() - start) / 1000.0d;
                    deploymentTable.addRow(sourceFile.toString(), String.valueOf(destinationFile), String.format("%.3f s", time));
                }
                Table diagnosticsTable = optionsByType.get(Table.class);
                if (diagnosticsTable != null) {
                    diagnosticsTable.addRow("Application Deployments ", deploymentTable.toString());
                }
            } catch (IOException | SftpException e) {
                throw new RuntimeException("Failed to deploy application", e);
            } finally {
                if (sftpChannel != null) {
                    sftpChannel.disconnect();
                }
            }
        }
    } catch (JSchException e) {
        throw new RuntimeException("Failed to deploy application", e);
    } finally {
        if (session != null) {
            session.disconnect();
        }
    }
    return deployedArtifacts;
}
Also used : JSchException(com.jcraft.jsch.JSchException) PlatformSeparators(com.oracle.bedrock.runtime.options.PlatformSeparators) Table(com.oracle.bedrock.table.Table) DeployedArtifacts(com.oracle.bedrock.runtime.remote.DeployedArtifacts) SftpException(com.jcraft.jsch.SftpException) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream) ChannelSftp(com.jcraft.jsch.ChannelSftp) Authentication(com.oracle.bedrock.runtime.remote.Authentication) OptionsByType(com.oracle.bedrock.OptionsByType) File(java.io.File) DeploymentArtifact(com.oracle.bedrock.runtime.remote.DeploymentArtifact) RemotePlatform(com.oracle.bedrock.runtime.remote.RemotePlatform) Session(com.jcraft.jsch.Session)

Example 3 with PlatformSeparators

use of com.oracle.bedrock.runtime.options.PlatformSeparators in project oracle-bedrock by coherence-community.

the class FileShareDeployer method deploy.

@Override
public DeployedArtifacts deploy(List<DeploymentArtifact> artifactsToDeploy, String remoteDirectory, Platform platform, Option... deploymentOptions) {
    DeployedArtifacts deployedArtifacts = new DeployedArtifacts();
    OptionsByType combinedOptions = platform == null ? OptionsByType.empty() : OptionsByType.of(platform.getOptions());
    Table deploymentTable = new Table();
    combinedOptions.addAll(optionsByType);
    combinedOptions.addAll(deploymentOptions);
    PlatformSeparators separators = combinedOptions.get(PlatformSeparators.class);
    File remoteShareFile = new File(remoteShareName);
    for (DeploymentArtifact artifact : artifactsToDeploy) {
        double start = System.currentTimeMillis();
        try {
            File sourceFile = artifact.getSourceFile();
            Path localCopy = new File(localShareName, sourceFile.getName()).toPath();
            Files.copy(artifact.getSourceFile().toPath(), localCopy, StandardCopyOption.REPLACE_EXISTING);
            String destination;
            String sourceName = artifact.getSourceFile().getName();
            File destinationFile = artifact.getDestinationFile();
            if (destinationFile == null) {
                destination = remoteDirectory + separators.getFileSeparator() + sourceName;
            } else {
                String destinationFilePath = separators.asPlatformFileName(destinationFile.getParent());
                String dirName;
                if (destinationFilePath == null) {
                    dirName = separators.asPlatformFileName(remoteDirectory);
                    destination = dirName + separators.getFileSeparator() + destinationFile.getPath();
                } else {
                    destination = separators.asPlatformFileName(destinationFile.getCanonicalPath());
                }
            }
            String source = new File(remoteShareFile, sourceName).getCanonicalPath();
            if (!source.equals(destination)) {
                boolean cleanup = performRemoteCopy(source, destination, platform, combinedOptions);
                if (cleanup) {
                    Files.delete(localCopy);
                }
            }
            // add the file as a deployed artifact
            deployedArtifacts.add(new File(destination));
            double time = (System.currentTimeMillis() - start) / 1000.0d;
            deploymentTable.addRow(sourceFile.toString(), String.valueOf(destination), String.format("%.3f s", time));
        } catch (IOException e) {
            throw new RuntimeException("Failed to deploy " + artifact, e);
        }
    }
    Table diagnosticsTable = optionsByType.get(Table.class);
    if (diagnosticsTable != null) {
        diagnosticsTable.addRow("Application Deployments ", deploymentTable.toString());
    }
    return deployedArtifacts;
}
Also used : Path(java.nio.file.Path) PlatformSeparators(com.oracle.bedrock.runtime.options.PlatformSeparators) Table(com.oracle.bedrock.table.Table) DeployedArtifacts(com.oracle.bedrock.runtime.remote.DeployedArtifacts) IOException(java.io.IOException) OptionsByType(com.oracle.bedrock.OptionsByType) File(java.io.File) DeploymentArtifact(com.oracle.bedrock.runtime.remote.DeploymentArtifact)

Example 4 with PlatformSeparators

use of com.oracle.bedrock.runtime.options.PlatformSeparators in project oracle-bedrock by coherence-community.

the class RemoteJavaApplicationLauncher method onLaunching.

@Override
protected void onLaunching(OptionsByType optionsByType) {
    // ----- establish default Profiles for this Platform (and Builder) -----
    // java applications can automatically detect the following profiles
    optionsByType.get(RemoteDebugging.class);
    optionsByType.get(CommercialFeatures.class);
    // ----- determine the remote classpath based on the deployment option -----
    // when no deployment is specified we assume automatic
    JavaDeployment deployment = (JavaDeployment) optionsByType.getOrSetDefault(Deployment.class, JavaDeployment.automatic());
    if (deployment.isAutoDeployEnabled()) {
        // determine the PlatformSeparators (assume unix if not defined)
        PlatformSeparators separators = optionsByType.getOrSetDefault(PlatformSeparators.class, PlatformSeparators.forUnix());
        // when an automatic deployment is specified,
        // we use our modified class-path
        // (which is where all of the deployed jars will be located)
        String thisDir = ".";
        String thisDirAllJars = thisDir + separators.getFileSeparator() + "*";
        remoteClassPath = new ClassPath(thisDir, thisDirAllJars);
    } else {
        // when a non-automatic deployment is specified we use the specified class path
        remoteClassPath = optionsByType.get(ClassPath.class);
    }
    // register the defined RemoteEventListeners before the application starts so they can
    // immediately start receiving RemoteEvents
    RemoteEvents remoteEvents = optionsByType.get(RemoteEvents.class);
    remoteEvents.forEach((remoteEventListener, listenerOptions) -> remoteChannel.addListener(remoteEventListener, listenerOptions));
}
Also used : PlatformSeparators(com.oracle.bedrock.runtime.options.PlatformSeparators) ClassPath(com.oracle.bedrock.runtime.java.ClassPath) RemoteEvents(com.oracle.bedrock.runtime.java.options.RemoteEvents) Deployment(com.oracle.bedrock.runtime.remote.options.Deployment) JavaDeployment(com.oracle.bedrock.runtime.remote.java.options.JavaDeployment) JavaDeployment(com.oracle.bedrock.runtime.remote.java.options.JavaDeployment)

Example 5 with PlatformSeparators

use of com.oracle.bedrock.runtime.options.PlatformSeparators in project oracle-bedrock by coherence-community.

the class RemoteJavaApplicationLauncher method getCommandToExecute.

@Override
public String getCommandToExecute(Platform platform, OptionsByType optionsByType) {
    StringBuilder commandBuilder = new StringBuilder();
    // ----- establish the command to start java -----
    JavaHome javaHome = optionsByType.get(JavaHome.class);
    // determine the Executable, defaulting to "java" if not defined
    Executable executable = optionsByType.getOrSetDefault(Executable.class, Executable.named("java"));
    if (javaHome == null) {
        // when we don't have a java home we just use the defined executable
        commandBuilder.append(StringHelper.doubleQuoteIfNecessary(executable.getName()));
    } else {
        // determine the PlatformSeparators (assume unix if not defined)
        PlatformSeparators separators = optionsByType.getOrSetDefault(PlatformSeparators.class, PlatformSeparators.forUnix());
        // when we have a java home, we prefix the executable name with the java.home/bin/
        String javaHomePath = javaHome.get().trim();
        String javaExecutable = javaHomePath;
        if (!javaHomePath.endsWith(separators.getFileSeparator())) {
            javaExecutable += separators.getFileSeparator();
        }
        javaExecutable += "bin";
        javaExecutable += separators.getFileSeparator();
        javaExecutable += executable.getName();
        commandBuilder.append(StringHelper.doubleQuoteIfNecessary(javaExecutable));
        Table diagnosticsTable = optionsByType.get(Table.class);
        if (diagnosticsTable != null) {
            diagnosticsTable.addRow("Java Home", javaHomePath);
            diagnosticsTable.addRow("Java Executable", javaExecutable);
        }
    }
    return commandBuilder.toString();
}
Also used : PlatformSeparators(com.oracle.bedrock.runtime.options.PlatformSeparators) Table(com.oracle.bedrock.table.Table) JavaHome(com.oracle.bedrock.runtime.java.options.JavaHome) Executable(com.oracle.bedrock.runtime.options.Executable)

Aggregations

PlatformSeparators (com.oracle.bedrock.runtime.options.PlatformSeparators)11 Table (com.oracle.bedrock.table.Table)5 File (java.io.File)5 OptionsByType (com.oracle.bedrock.OptionsByType)3 DeploymentArtifact (com.oracle.bedrock.runtime.remote.DeploymentArtifact)3 IOException (java.io.IOException)3 Test (org.junit.Test)3 Profile (com.oracle.bedrock.runtime.Profile)2 Executable (com.oracle.bedrock.runtime.options.Executable)2 DeployedArtifacts (com.oracle.bedrock.runtime.remote.DeployedArtifacts)2 Deployment (com.oracle.bedrock.runtime.remote.options.Deployment)2 ArrayList (java.util.ArrayList)2 ChannelSftp (com.jcraft.jsch.ChannelSftp)1 JSchException (com.jcraft.jsch.JSchException)1 Session (com.jcraft.jsch.Session)1 SftpException (com.jcraft.jsch.SftpException)1 DiagnosticsRecording (com.oracle.bedrock.diagnostics.DiagnosticsRecording)1 ApplicationListener (com.oracle.bedrock.runtime.ApplicationListener)1 ApplicationProcess (com.oracle.bedrock.runtime.ApplicationProcess)1 ClassPath (com.oracle.bedrock.runtime.java.ClassPath)1