Package com.sun.enterprise.admin.cli.cluster

Source Code of com.sun.enterprise.admin.cli.cluster.InstallNodeSshCommand

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.admin.cli.cluster;

import com.sun.enterprise.util.SystemPropertyConstants;
import com.sun.enterprise.util.io.FileUtils;
import com.trilead.ssh2.SCPClient;
import com.trilead.ssh2.SFTPv3DirectoryEntry;
import java.io.*;
import java.io.ByteArrayOutputStream;
import java.util.*;
import org.glassfish.api.Param;
import org.glassfish.api.admin.CommandException;
import org.glassfish.cluster.ssh.launcher.SSHLauncher;
import org.glassfish.cluster.ssh.sftp.SFTPClient;
import org.glassfish.cluster.ssh.util.SSHUtil;
import org.jvnet.hk2.annotations.*;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.component.PerLookup;

/**
* @author Byron Nevins
*/
@Service(name = "install-node-ssh")
@Scoped(PerLookup.class)
public class InstallNodeSshCommand extends InstallNodeBaseCommand {
    @Param(name = "sshuser", optional = true, defaultValue = "${user.name}")
    private String user;
    @Param(optional = true, defaultValue = "22", name = "sshport")
    int port;
    @Param(optional = true)
    String sshkeyfile;
    @Inject
    private SSHLauncher sshLauncher;
    //storing password to prevent prompting twice
    private Map<String, char[]> sshPasswords = new HashMap<String, char[]>();

    @Override
    String getRawRemoteUser() {
        return user;
    }

    @Override
    int getRawRemotePort() {
        return port;
    }

    @Override
    String getSshKeyFile() {
        return sshkeyfile;
    }

    @Override
    protected void validate() throws CommandException {
        super.validate();
        if (sshkeyfile == null) {
            //if user hasn't specified a key file check if key exists in
            //default location
            String existingKey = SSHUtil.getExistingKeyFile();
            if (existingKey == null) {
                promptPass = true;
            }
            else {
                sshkeyfile = existingKey;
            }
        }
        else {
            validateKey(sshkeyfile);
        }

        //we need the key passphrase if key is encrypted
        if (sshkeyfile != null && SSHUtil.isEncryptedKey(sshkeyfile)) {
            sshkeypassphrase = getSSHPassphrase(true);
        }
    }

    @Override
    void copyToHosts(File zipFile, ArrayList<String> binDirFiles) throws CommandException {
        // exception handling is too complicated to mess with in the real method.
        // the idea is to catch everything here and re-throw as one kind
        // the caller is just going to do it anyway so we may as well do it here.
        // And it makes the signature simpler for other subclasses...
        try {
            copyToHostsInternal(zipFile, binDirFiles);
        }
        catch (CommandException ex) {
            throw ex;
        }
        catch (IOException ex) {
            throw new CommandException(ex);
        }
        catch (InterruptedException ex) {
            throw new CommandException(ex);
        }
    }

    private void copyToHostsInternal(File zipFile, ArrayList<String> binDirFiles) throws IOException, InterruptedException, CommandException {

        ByteArrayOutputStream outStream = new ByteArrayOutputStream();

        boolean prompt = promptPass;
        for (String host : hosts) {
            sshLauncher.init(getRemoteUser(), host, getRemotePort(), sshpassword, getSshKeyFile(), sshkeypassphrase, logger);

            if (getSshKeyFile() != null && !sshLauncher.checkConnection()) {
                //key auth failed, so use password auth
                prompt = true;
            }

            if (prompt) {
                String sshpass = null;
                if (sshPasswords.containsKey(host))
                    sshpass = String.valueOf(sshPasswords.get(host));
                else
                    sshpass = getSSHPassword(host);

                //re-initialize
                sshLauncher.init(getRemoteUser(), host, getRemotePort(), sshpass, getSshKeyFile(), sshkeypassphrase, logger);
                prompt = false;
            }

            String sshInstallDir = getInstallDir().replace('\\', '/');

            SFTPClient sftpClient = sshLauncher.getSFTPClient();
            SCPClient scpClient = sshLauncher.getSCPClient();
            try {
                if (!sftpClient.exists(sshInstallDir)) {
                    sftpClient.mkdirs(sshInstallDir, 0755);
                }
            }
            catch (IOException ioe) {
                logger.info(Strings.get("mkdir.failed", sshInstallDir, host));
                throw new IOException(ioe);
            }

            //delete the sshInstallDir contents if non-empty
            try {
                //get list of file in DAS sshInstallDir
                List<String> files = getListOfInstallFiles(sshInstallDir);
                deleteRemoteFiles(sftpClient, files, sshInstallDir, getForce());
            }
            catch (IOException ex) {
                logger.finer("Failed to remove sshInstallDir contents");
                throw new IOException(ex);
            }

            String zip = zipFile.getCanonicalPath();
            try {
                logger.info("Copying " + zip + " (" + zipFile.length() + " bytes)"
                        + " to " + host + ":" + sshInstallDir);
                // Looks like we need to quote the paths to scp in case they
                // contain spaces.
                scpClient.put(zipFile.getAbsolutePath(), FileUtils.quoteString(sshInstallDir));
                logger.finer("Copied " + zip + " to " + host + ":" + sshInstallDir);
            }
            catch (IOException ex) {
                logger.info(Strings.get("cannot.copy.zip.file", zip, host));
                throw new IOException(ex);
            }

            try {
                logger.info("Installing " + getArchiveName() + " into " + host + ":" + sshInstallDir);
                String unzipCommand = "cd '" + sshInstallDir + "'; jar -xvf " + getArchiveName();
                int status = sshLauncher.runCommand(unzipCommand, outStream);
                if (status != 0) {
                    logger.info(Strings.get("jar.failed", host, outStream.toString()));
                    throw new CommandException("Remote command output: " + outStream.toString());
                }
                logger.finer("Installed " + getArchiveName() + " into " + host + ":" + sshInstallDir);
            }
            catch (IOException ioe) {
                logger.info(Strings.get("jar.failed", host, outStream.toString()));
                throw new IOException(ioe);
            }

            try {
                logger.info("Removing " + host + ":" + sshInstallDir + "/" + getArchiveName());
                sftpClient.rm(sshInstallDir + "/" + getArchiveName());
                logger.finer("Removed " + host + ":" + sshInstallDir + "/" + getArchiveName());
            }
            catch (IOException ioe) {
                logger.info(Strings.get("remove.glassfish.failed", host, sshInstallDir));
                throw new IOException(ioe);
            }

            // unjarring doesn't retain file permissions, hence executables need
            // to be fixed with proper permissions
            logger.info("Fixing file permissions of all bin files under " + host + ":" + sshInstallDir);
            try {
                if (binDirFiles.isEmpty()) {
                    //binDirFiles can be empty if the archive isn't a fresh one
                    searchAndFixBinDirectoryFiles(sshInstallDir, sftpClient);
                }
                else {
                    for (String binDirFile : binDirFiles) {
                        sftpClient.chmod((sshInstallDir + "/" + binDirFile), 0755);
                    }
                }
                logger.finer("Fixed file permissions of all bin files under " + host + ":" + sshInstallDir);
            }
            catch (IOException ioe) {
                logger.info(Strings.get("fix.permissions.failed", host, sshInstallDir));
                throw new IOException(ioe);
            }

            if (Constants.v4) {
                logger.info("Fixing file permissions for nadmin file under " + host + ":"
                            + sshInstallDir + "/" + SystemPropertyConstants.getComponentName() + "/lib");
                try {
                    sftpClient.chmod((sshInstallDir + "/" + SystemPropertyConstants.getComponentName() + "/lib/nadmin"), 0755);
                    logger.finer("Fixed file permission for nadmin under " + host + ":" + sshInstallDir + "/" + SystemPropertyConstants.getComponentName() + "/lib/nadmin");
                }
                catch (IOException ioe) {
                    logger.info(Strings.get("fix.permissions.failed", host, sshInstallDir));
                    throw new IOException(ioe);
                }
            }
        }
    }
   
    /**
     * Recursively list install dir and identify "bin" directory. Change permissions
     * of files under "bin" directory.
     * @param installDir GlassFish install root
     * @param sftpClient ftp client handle
     * @throws IOException
     */
    private void searchAndFixBinDirectoryFiles(String installDir, SFTPClient sftpClient) throws IOException {
        for (SFTPv3DirectoryEntry directoryEntry : (List<SFTPv3DirectoryEntry>) sftpClient.ls(installDir)) {
            if (directoryEntry.filename.equals(".") || directoryEntry.filename.equals(".."))
                continue;
            else if (directoryEntry.attributes.isDirectory()) {
                String subDir = installDir + "/" + directoryEntry.filename;
                if (directoryEntry.filename.equals("bin")) {
                    fixAllFiles(subDir, sftpClient);
                } else {
                    searchAndFixBinDirectoryFiles(subDir, sftpClient);
                }  
            }
        }
    }

    /**
     * Set permissions of all files under specified directory. Note that this
     * doesn't check the file type before changing the permissions.
     * @param binDir directory where file permissions need to be fixed
     * @param sftpClient ftp client handle
     * @throws IOException
     */
    private void fixAllFiles(String binDir, SFTPClient sftpClient) throws IOException {
        for (SFTPv3DirectoryEntry directoryEntry : (List<SFTPv3DirectoryEntry>) sftpClient.ls(binDir)) {
            if (directoryEntry.filename.equals(".") || directoryEntry.filename.equals(".."))
                continue;
            else {
                String fName = binDir + "/" + directoryEntry.filename;
                sftpClient.chmod(fName, 0755);
            }
        }
    }
   
    /**
     * Determines if GlassFish is installed on remote host at specified location.
     * Uses SSH launcher to execute 'asadmin version'
     * @param host remote host
     * @throws CommandException
     * @throws IOException
     * @throws InterruptedException
     */
    private void checkIfAlreadyInstalled(String host, String sshInstallDir) throws CommandException, IOException, InterruptedException {
        //check if an installation already exists on remote host
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        try {
            String asadmin = Constants.v4 ? "/lib/nadmin' version --local --terse" : "/bin/asadmin' version --local --terse";
            String cmd = "'" + sshInstallDir + "/" + SystemPropertyConstants.getComponentName() + asadmin;
            int status = sshLauncher.runCommand(cmd, outStream);
            if (status == 0) {
                logger.finer(host + ":'" + cmd + "'" + " returned [" + outStream.toString() + "]");
                throw new CommandException(Strings.get("install.dir.exists", sshInstallDir));
            }
            else {
                logger.finer(host + ":'" + cmd + "'" + " failed [" + outStream.toString() + "]");
            }
        }
        catch (IOException ex) {
            logger.info(Strings.get("glassfish.install.check.failed", host));
            throw new IOException(ex);
        }
    }

    @Override
    final void precopy() throws CommandException {
        if (getForce())
            return;
       
        boolean prompt = promptPass;
        for (String host : hosts) {
            sshLauncher.init(getRemoteUser(), host, getRemotePort(), sshpassword, getSshKeyFile(), sshkeypassphrase, logger);

            if (getSshKeyFile() != null && !sshLauncher.checkConnection()) {
                //key auth failed, so use password auth
                prompt = true;
            }

            if (prompt) {
                String sshpass = getSSHPassword(host);
                sshPasswords.put(host, sshpass.toCharArray());
                //re-initialize
                sshLauncher.init(getRemoteUser(), host, getRemotePort(), sshpass, getSshKeyFile(), sshkeypassphrase, logger);
                prompt = false;
            }

            String sshInstallDir = getInstallDir().replaceAll("\\\\", "/");

            try {
                SFTPClient sftpClient = sshLauncher.getSFTPClient();
                if (sftpClient.exists(sshInstallDir)){
                    checkIfAlreadyInstalled(host, sshInstallDir);
                }
            }
            catch (IOException ex) {
                throw new CommandException(ex);
            }
            catch (InterruptedException ex) {
                throw new CommandException(ex);
            }
        }
    }
}
TOP

Related Classes of com.sun.enterprise.admin.cli.cluster.InstallNodeSshCommand

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.