Merge pull request #219 from future-architect/confirm-before-preparing
Confirm before installing dependencies on prepare
This commit is contained in:
		@@ -149,10 +149,9 @@ func (p *PrepareCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{
 | 
			
		||||
		return subcommands.ExitFailure
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logger.Info("Installing...")
 | 
			
		||||
	if errs := scan.Prepare(); 0 < len(errs) {
 | 
			
		||||
		for _, e := range errs {
 | 
			
		||||
			logger.Errorf("Failed: %s", e)
 | 
			
		||||
			logger.Errorf("Failed to prepare: %s", e)
 | 
			
		||||
		}
 | 
			
		||||
		return subcommands.ExitFailure
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,8 +33,9 @@ import (
 | 
			
		||||
type base struct {
 | 
			
		||||
	ServerInfo config.ServerInfo
 | 
			
		||||
	Distro     config.Distro
 | 
			
		||||
	Platform   models.Platform
 | 
			
		||||
 | 
			
		||||
	Platform models.Platform
 | 
			
		||||
	lackDependencies []string
 | 
			
		||||
	osPackages
 | 
			
		||||
 | 
			
		||||
	log  *logrus.Entry
 | 
			
		||||
@@ -77,6 +78,10 @@ func (l base) getPlatform() models.Platform {
 | 
			
		||||
	return l.Platform
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l base) getLackDependencies() []string {
 | 
			
		||||
	return l.lackDependencies
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l base) allContainers() (containers []config.Container, err error) {
 | 
			
		||||
	switch l.ServerInfo.Container.Type {
 | 
			
		||||
	case "", "docker":
 | 
			
		||||
 
 | 
			
		||||
@@ -124,7 +124,31 @@ func (o *debian) checkIfSudoNoPasswd() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *debian) checkDependencies() error {
 | 
			
		||||
	switch o.Distro.Family {
 | 
			
		||||
	case "ubuntu":
 | 
			
		||||
		return nil
 | 
			
		||||
 | 
			
		||||
	case "debian":
 | 
			
		||||
		// Debian needs aptitude to get changelogs.
 | 
			
		||||
		// Because unable to get changelogs via apt-get changelog on Debian.
 | 
			
		||||
		name := "aptitude"
 | 
			
		||||
		cmd := name + " -h"
 | 
			
		||||
		if r := o.ssh(cmd, noSudo); !r.isSuccess() {
 | 
			
		||||
			o.lackDependencies = []string{name}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("Not implemented yet: %s", o.Distro)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *debian) install() error {
 | 
			
		||||
	if len(o.lackDependencies) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// apt-get update
 | 
			
		||||
	o.log.Infof("apt-get update...")
 | 
			
		||||
	cmd := util.PrependProxyEnv("apt-get update")
 | 
			
		||||
@@ -134,15 +158,14 @@ func (o *debian) install() error {
 | 
			
		||||
		return fmt.Errorf(msg)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.Distro.Family == "debian" {
 | 
			
		||||
		// install aptitude
 | 
			
		||||
		cmd = util.PrependProxyEnv("apt-get install --force-yes -y aptitude")
 | 
			
		||||
	for _, name := range o.lackDependencies {
 | 
			
		||||
		cmd = util.PrependProxyEnv("apt-get install " + name)
 | 
			
		||||
		if r := o.ssh(cmd, sudo); !r.isSuccess() {
 | 
			
		||||
			msg := fmt.Sprintf("Failed to SSH: %s", r)
 | 
			
		||||
			o.log.Errorf(msg)
 | 
			
		||||
			return fmt.Errorf(msg)
 | 
			
		||||
		}
 | 
			
		||||
		o.log.Infof("Installed: aptitude")
 | 
			
		||||
		o.log.Infof("Installed: " + name)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,10 @@ func (o *bsd) checkIfSudoNoPasswd() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *bsd) checkDependencies() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *bsd) install() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -112,45 +112,46 @@ func (o *redhat) checkIfSudoNoPasswd() error {
 | 
			
		||||
// CentOS 6 ... yum-plugin-changelog
 | 
			
		||||
// CentOS 7 ... yum-plugin-changelog
 | 
			
		||||
// RHEL, Amazon ... no additinal packages needed
 | 
			
		||||
func (o *redhat) install() error {
 | 
			
		||||
func (o *redhat) checkDependencies() error {
 | 
			
		||||
	switch o.Distro.Family {
 | 
			
		||||
	case "rhel", "amazon":
 | 
			
		||||
		o.log.Infof("Nothing to do")
 | 
			
		||||
		//  o.log.Infof("Nothing to do")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	// CentOS
 | 
			
		||||
	return o.installYumChangelog()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *redhat) installYumChangelog() error {
 | 
			
		||||
	if o.Distro.Family == "centos" {
 | 
			
		||||
	case "centos":
 | 
			
		||||
		var majorVersion int
 | 
			
		||||
		if 0 < len(o.Distro.Release) {
 | 
			
		||||
			majorVersion, _ = strconv.Atoi(strings.Split(o.Distro.Release, ".")[0])
 | 
			
		||||
		} else {
 | 
			
		||||
			return fmt.Errorf(
 | 
			
		||||
				"Not implemented yet: %s", o.Distro)
 | 
			
		||||
			return fmt.Errorf("Not implemented yet: %s", o.Distro)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var packName = ""
 | 
			
		||||
		var name = ""
 | 
			
		||||
		if majorVersion < 6 {
 | 
			
		||||
			packName = "yum-changelog"
 | 
			
		||||
			name = "yum-changelog"
 | 
			
		||||
		} else {
 | 
			
		||||
			packName = "yum-plugin-changelog"
 | 
			
		||||
			name = "yum-plugin-changelog"
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cmd := "rpm -q " + packName
 | 
			
		||||
		cmd := "rpm -q " + name
 | 
			
		||||
		if r := o.ssh(cmd, noSudo); r.isSuccess() {
 | 
			
		||||
			o.log.Infof("Ignored: %s already installed", packName)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		o.lackDependencies = []string{name}
 | 
			
		||||
		return nil
 | 
			
		||||
 | 
			
		||||
		o.log.Infof("Installing %s...", packName)
 | 
			
		||||
		cmd = util.PrependProxyEnv("yum install -y " + packName)
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("Not implemented yet: %s", o.Distro)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *redhat) install() error {
 | 
			
		||||
	for _, name := range o.lackDependencies {
 | 
			
		||||
		cmd := util.PrependProxyEnv("yum install -y " + name)
 | 
			
		||||
		if r := o.ssh(cmd, sudo); !r.isSuccess() {
 | 
			
		||||
			return fmt.Errorf("Failed to SSH: %s", r)
 | 
			
		||||
		}
 | 
			
		||||
		o.log.Infof("Installed: %s", packName)
 | 
			
		||||
		o.log.Infof("Installed: %s", name)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
package scan
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
@@ -40,7 +43,10 @@ type osTypeInterface interface {
 | 
			
		||||
 | 
			
		||||
	setDistro(string, string)
 | 
			
		||||
	getDistro() config.Distro
 | 
			
		||||
	//  getFamily() string
 | 
			
		||||
 | 
			
		||||
	// checkDependencies checks if dependencies are installed on the target server.
 | 
			
		||||
	checkDependencies() error
 | 
			
		||||
	getLackDependencies() []string
 | 
			
		||||
 | 
			
		||||
	checkIfSudoNoPasswd() error
 | 
			
		||||
	detectPlatform() error
 | 
			
		||||
@@ -60,7 +66,7 @@ type osTypeInterface interface {
 | 
			
		||||
	setErrs([]error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// osPackages included by linux struct
 | 
			
		||||
// osPackages is included by base struct
 | 
			
		||||
type osPackages struct {
 | 
			
		||||
	// installed packages
 | 
			
		||||
	Packages models.PackageInfoList
 | 
			
		||||
@@ -425,12 +431,65 @@ func detectPlatforms() []error {
 | 
			
		||||
 | 
			
		||||
// Prepare installs requred packages to scan vulnerabilities.
 | 
			
		||||
func Prepare() []error {
 | 
			
		||||
	return parallelSSHExec(func(o osTypeInterface) error {
 | 
			
		||||
	errs := parallelSSHExec(func(o osTypeInterface) error {
 | 
			
		||||
		if err := o.checkDependencies(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
	if len(errs) != 0 {
 | 
			
		||||
		return errs
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var targets []osTypeInterface
 | 
			
		||||
	for _, s := range servers {
 | 
			
		||||
		deps := s.getLackDependencies()
 | 
			
		||||
		if len(deps) != 0 {
 | 
			
		||||
			targets = append(targets, s)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(targets) == 0 {
 | 
			
		||||
		Log.Info("No need to install dependencies")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Log.Info("Below servers are needed to install dependencies")
 | 
			
		||||
	for _, s := range targets {
 | 
			
		||||
		for _, d := range s.getLackDependencies() {
 | 
			
		||||
			Log.Infof("  - %s on %s", d, s.getServerInfo().GetServerName())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	Log.Info("Is this ok to install dependencies on the servers? [y/N]")
 | 
			
		||||
 | 
			
		||||
	reader := bufio.NewReader(os.Stdin)
 | 
			
		||||
	for {
 | 
			
		||||
		text, err := reader.ReadString('\n')
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return []error{err}
 | 
			
		||||
		}
 | 
			
		||||
		switch strings.TrimSpace(text) {
 | 
			
		||||
		case "", "N", "n":
 | 
			
		||||
			return nil
 | 
			
		||||
		case "y", "Y":
 | 
			
		||||
			goto yes
 | 
			
		||||
		default:
 | 
			
		||||
			Log.Info("Please enter y or N")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
yes:
 | 
			
		||||
	servers = targets
 | 
			
		||||
	errs = parallelSSHExec(func(o osTypeInterface) error {
 | 
			
		||||
		if err := o.install(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
	if len(errs) != 0 {
 | 
			
		||||
		return errs
 | 
			
		||||
	}
 | 
			
		||||
	Log.Info("All dependencies were installed correctly")
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Scan scan
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user