github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/provider/local/prereqs_linux.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package local
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"os"
    10  	"os/exec"
    11  	"regexp"
    12  	"runtime"
    13  
    14  	"launchpad.net/juju-core/agent/mongo"
    15  	"launchpad.net/juju-core/container/kvm"
    16  	"launchpad.net/juju-core/instance"
    17  	"launchpad.net/juju-core/utils"
    18  	"launchpad.net/juju-core/version"
    19  )
    20  
    21  var notLinuxError = errors.New("The local provider is currently only available for Linux")
    22  
    23  const installMongodUbuntu = "MongoDB server must be installed to enable the local provider:"
    24  const aptAddRepositoryJujuStable = `
    25      sudo apt-add-repository ppa:juju/stable   # required for MongoDB SSL support
    26      sudo apt-get update`
    27  const aptGetInstallMongodbServer = `
    28      sudo apt-get install mongodb-server`
    29  
    30  const installMongodGeneric = `
    31  MongoDB server must be installed to enable the local provider.
    32  Please consult your operating system distribution's documentation
    33  for instructions on installing the MongoDB server. Juju requires
    34  a MongoDB server built with SSL support.
    35  `
    36  
    37  const installLxcUbuntu = `
    38  Linux Containers (LXC) userspace tools must be
    39  installed to enable the local provider:
    40  
    41      sudo apt-get install lxc`
    42  
    43  const installRsyslogGnutlsUbuntu = `
    44  rsyslog-gnutls must be installed to enable the local provider:
    45  
    46      sudo apt-get install rsyslog-gnutls`
    47  
    48  const installRsyslogGnutlsGeneric = `
    49  rsyslog-gnutls must be installed to enable the local provider.
    50  Please consult your operating system distribution's documentation
    51  for instructions on installing this package.`
    52  
    53  const installLxcGeneric = `
    54  Linux Containers (LXC) userspace tools must be installed to enable the
    55  local provider. Please consult your operating system distribution's
    56  documentation for instructions on installing the LXC userspace tools.`
    57  
    58  const errUnsupportedOS = `Unsupported operating system: %s
    59  The local provider is currently only available for Linux`
    60  
    61  // lowestMongoVersion is the lowest version of mongo that juju supports.
    62  var lowestMongoVersion = version.Number{Major: 2, Minor: 2, Patch: 4}
    63  
    64  // lxclsPath is the path to "lxc-ls", an LXC userspace tool
    65  // we check the presence of to determine whether the
    66  // tools are installed. This is a variable only to support
    67  // unit testing.
    68  var lxclsPath = "lxc-ls"
    69  
    70  // isPackageInstalled is a variable to support testing.
    71  var isPackageInstalled = utils.IsPackageInstalled
    72  
    73  // defaultRsyslogGnutlsPath is the default path to the
    74  // rsyslog GnuTLS module. This is a variable only to
    75  // support unit testing.
    76  var defaultRsyslogGnutlsPath = "/usr/lib/rsyslog/lmnsd_gtls.so"
    77  
    78  // The operating system the process is running in.
    79  // This is a variable only to support unit testing.
    80  var goos = runtime.GOOS
    81  
    82  // This is the regex for processing the results of mongod --verison
    83  var mongoVerRegex = regexp.MustCompile(`db version v(\d+\.\d+\.\d+)`)
    84  
    85  // VerifyPrerequisites verifies the prerequisites of
    86  // the local machine (machine 0) for running the local
    87  // provider.
    88  func VerifyPrerequisites(containerType instance.ContainerType) error {
    89  	if goos != "linux" {
    90  		return fmt.Errorf(errUnsupportedOS, goos)
    91  	}
    92  	if err := verifyMongod(); err != nil {
    93  		return err
    94  	}
    95  	if err := verifyRsyslogGnutls(); err != nil {
    96  		return err
    97  	}
    98  	switch containerType {
    99  	case instance.LXC:
   100  		return verifyLxc()
   101  	case instance.KVM:
   102  		return kvm.VerifyKVMEnabled()
   103  	}
   104  	return fmt.Errorf("Unknown container type specified in the config.")
   105  }
   106  
   107  func verifyMongod() error {
   108  	path, err := mongo.MongodPath()
   109  	if err != nil {
   110  		return wrapMongodNotExist(err)
   111  	}
   112  
   113  	ver, err := mongodVersion(path)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	if ver.Compare(lowestMongoVersion) < 0 {
   118  		return fmt.Errorf("installed version of mongod (%v) is not supported by Juju. "+
   119  			"Juju requires version %v or greater.",
   120  			ver,
   121  			lowestMongoVersion)
   122  	}
   123  	return nil
   124  }
   125  
   126  func mongodVersion(path string) (version.Number, error) {
   127  	data, err := utils.RunCommand(path, "--version")
   128  	if err != nil {
   129  		return version.Zero, wrapMongodNotExist(err)
   130  	}
   131  
   132  	return parseVersion(data)
   133  }
   134  
   135  func parseVersion(data string) (version.Number, error) {
   136  	matches := mongoVerRegex.FindStringSubmatch(data)
   137  	if len(matches) < 2 {
   138  		return version.Zero, errors.New("could not parse mongod version")
   139  	}
   140  	return version.Parse(matches[1])
   141  }
   142  
   143  func verifyLxc() error {
   144  	_, err := exec.LookPath(lxclsPath)
   145  	if err != nil {
   146  		return wrapLxcNotFound(err)
   147  	}
   148  	return nil
   149  }
   150  
   151  func verifyRsyslogGnutls() error {
   152  	if isPackageInstalled("rsyslog-gnutls") {
   153  		return nil
   154  	}
   155  	if utils.IsUbuntu() {
   156  		return errors.New(installRsyslogGnutlsUbuntu)
   157  	}
   158  	// Not all Linuxes will distribute the module
   159  	// in the same way. Check if it's in the default
   160  	// location too.
   161  	_, err := os.Stat(defaultRsyslogGnutlsPath)
   162  	if err == nil {
   163  		return nil
   164  	}
   165  	return fmt.Errorf("%v\n%s", err, installRsyslogGnutlsGeneric)
   166  }
   167  
   168  func wrapMongodNotExist(err error) error {
   169  	if utils.IsUbuntu() {
   170  		series := version.Current.Series
   171  		args := []interface{}{err, installMongodUbuntu}
   172  		format := "%v\n%s\n%s"
   173  		if series == "precise" || series == "quantal" {
   174  			format += "%s"
   175  			args = append(args, aptAddRepositoryJujuStable)
   176  		}
   177  		args = append(args, aptGetInstallMongodbServer)
   178  		return fmt.Errorf(format, args...)
   179  	}
   180  	return fmt.Errorf("%v\n%s", err, installMongodGeneric)
   181  }
   182  
   183  func wrapLxcNotFound(err error) error {
   184  	if utils.IsUbuntu() {
   185  		return fmt.Errorf("%v\n%s", err, installLxcUbuntu)
   186  	}
   187  	return fmt.Errorf("%v\n%s", err, installLxcGeneric)
   188  }