github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cloudconfig/cloudinit/cloudinit_centos.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Copyright 2015 Cloudbase Solutions SRL
     3  // Licensed under the AGPLv3, see LICENCE file for details.
     4  
     5  package cloudinit
     6  
     7  import (
     8  	"fmt"
     9  	"strings"
    10  
    11  	"github.com/juju/juju/feature"
    12  	"github.com/juju/utils/featureflag"
    13  	"github.com/juju/utils/packaging"
    14  	"github.com/juju/utils/packaging/config"
    15  	"github.com/juju/utils/proxy"
    16  	"gopkg.in/yaml.v2"
    17  )
    18  
    19  // centOSCloudConfig is the cloudconfig type specific to CentOS machines.
    20  // It simply contains a cloudConfig and adds the package management related
    21  // methods for CentOS, which are mostly modeled as runcmds.
    22  // It implements the cloudinit.Config interface.
    23  type centOSCloudConfig struct {
    24  	*cloudConfig
    25  }
    26  
    27  // SetPackageProxy is defined on the PackageProxyConfig interface.
    28  func (cfg *centOSCloudConfig) SetPackageProxy(url string) {
    29  	cfg.SetAttr("package_proxy", url)
    30  }
    31  
    32  // addPackageProxyCmd is a helper function which returns the corresponding runcmd
    33  // to apply the package proxy settings on a CentOS machine.
    34  func addPackageProxyCmd(cfg CloudConfig, url string) string {
    35  	return fmt.Sprintf("/bin/echo 'proxy=%s' >> /etc/yum.conf", url)
    36  }
    37  
    38  // UnsetPackageProxy is defined on the PackageProxyConfig interface.
    39  func (cfg *centOSCloudConfig) UnsetPackageProxy() {
    40  	cfg.UnsetAttr("package_proxy")
    41  }
    42  
    43  // PackageProxy is defined on the PackageProxyConfig interface.
    44  func (cfg *centOSCloudConfig) PackageProxy() string {
    45  	proxy, _ := cfg.attrs["package_proxy"].(string)
    46  	return proxy
    47  }
    48  
    49  // SetPackageMirror is defined on the PackageMirrorConfig interface.
    50  func (cfg *centOSCloudConfig) SetPackageMirror(url string) {
    51  	cfg.SetAttr("package_mirror", url)
    52  }
    53  
    54  // addPackageMirrorCmd is a helper function that returns the corresponding runcmds
    55  // to apply the package mirror settings on a CentOS machine.
    56  func addPackageMirrorCmd(cfg CloudConfig, url string) string {
    57  	return fmt.Sprintf(config.ReplaceCentOSMirror, url)
    58  }
    59  
    60  // UnsetPackageMirror is defined on the PackageMirrorConfig interface.
    61  func (cfg *centOSCloudConfig) UnsetPackageMirror() {
    62  	cfg.UnsetAttr("package_mirror")
    63  }
    64  
    65  // PackageMirror is defined on the PackageMirrorConfig interface.
    66  func (cfg *centOSCloudConfig) PackageMirror() string {
    67  	mirror, _ := cfg.attrs["package_mirror"].(string)
    68  	return mirror
    69  }
    70  
    71  // AddPackageSource is defined on the PackageSourcesConfig interface.
    72  func (cfg *centOSCloudConfig) AddPackageSource(src packaging.PackageSource) {
    73  	cfg.attrs["package_sources"] = append(cfg.PackageSources(), src)
    74  }
    75  
    76  // PackageSources is defined on the PackageSourcesConfig interface.
    77  func (cfg *centOSCloudConfig) PackageSources() []packaging.PackageSource {
    78  	sources, _ := cfg.attrs["package_sources"].([]packaging.PackageSource)
    79  	return sources
    80  }
    81  
    82  // AddPackagePreferences is defined on the PackageSourcesConfig interface.
    83  func (cfg *centOSCloudConfig) AddPackagePreferences(prefs packaging.PackagePreferences) {
    84  	// TODO (aznashwan): research a way of using yum-priorities in the
    85  	// context of a single package and implement the appropriate runcmds.
    86  }
    87  
    88  // PackagePreferences is defined on the PackageSourcesConfig interface.
    89  func (cfg *centOSCloudConfig) PackagePreferences() []packaging.PackagePreferences {
    90  	// TODO (aznashwan): add this when priorities in yum make sense.
    91  	return []packaging.PackagePreferences{}
    92  }
    93  
    94  // Render is defined on the the Renderer interface.
    95  func (cfg *centOSCloudConfig) RenderYAML() ([]byte, error) {
    96  	// Save the fields that we will modify
    97  	var oldruncmds []string
    98  	oldruncmds = copyStringSlice(cfg.RunCmds())
    99  
   100  	// check for package proxy setting and add commands:
   101  	var proxy string
   102  	if proxy = cfg.PackageProxy(); proxy != "" {
   103  		cfg.AddRunCmd(addPackageProxyCmd(cfg, proxy))
   104  		cfg.UnsetPackageProxy()
   105  	}
   106  
   107  	// check for package mirror settings and add commands:
   108  	var mirror string
   109  	if mirror = cfg.PackageMirror(); mirror != "" {
   110  		cfg.AddRunCmd(addPackageMirrorCmd(cfg, mirror))
   111  		cfg.UnsetPackageMirror()
   112  	}
   113  
   114  	// add appropriate commands for package sources configuration:
   115  	srcs := cfg.PackageSources()
   116  	for _, src := range srcs {
   117  		cfg.AddScripts(addPackageSourceCmds(cfg, src)...)
   118  	}
   119  	cfg.UnsetAttr("package_sources")
   120  
   121  	data, err := yaml.Marshal(cfg.attrs)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	// Restore the modified fields
   127  	cfg.SetPackageProxy(proxy)
   128  	cfg.SetPackageMirror(mirror)
   129  	cfg.SetAttr("package_sources", srcs)
   130  	if oldruncmds != nil {
   131  		cfg.SetAttr("runcmd", oldruncmds)
   132  	} else {
   133  		cfg.UnsetAttr("runcmd")
   134  	}
   135  
   136  	return append([]byte("#cloud-config\n"), data...), nil
   137  }
   138  
   139  func (cfg *centOSCloudConfig) RenderScript() (string, error) {
   140  	return renderScriptCommon(cfg)
   141  }
   142  
   143  // AddCloudArchiveCloudTools is defined on the AdvancedPackagingConfig.
   144  func (cfg *centOSCloudConfig) AddCloudArchiveCloudTools() {
   145  	src, pref := config.GetCloudArchiveSource(cfg.series)
   146  	cfg.AddPackageSource(src)
   147  	cfg.AddPackagePreferences(pref)
   148  }
   149  
   150  func (cfg *centOSCloudConfig) getCommandsForAddingPackages() ([]string, error) {
   151  	var cmds []string
   152  
   153  	if newMirror := cfg.PackageMirror(); newMirror != "" {
   154  		cmds = append(cmds, LogProgressCmd("Changing package mirror does not yet work on CentOS"))
   155  		// TODO(bogdanteleaga, aznashwan): This should work after a further PR
   156  		// where we add more mirrror options values to environs.Config
   157  		cmds = append(cmds, addPackageMirrorCmd(cfg, newMirror))
   158  	}
   159  
   160  	for _, src := range cfg.PackageSources() {
   161  		// TODO(bogdanteleaga. aznashwan): Keys are usually offered by repositories, and you need to
   162  		// accept them. Check how this can be done non interactively.
   163  		cmds = append(cmds, LogProgressCmd("Adding yum repository: %s", src.URL))
   164  		cmds = append(cmds, cfg.paccmder.AddRepositoryCmd(src.URL))
   165  	}
   166  
   167  	// TODO(bogdanteleaga. aznashwan): Research what else needs to be done here
   168  
   169  	// Define the "package_get_loop" function
   170  	cmds = append(cmds, config.PackageManagerLoopFunction)
   171  
   172  	if cfg.SystemUpdate() {
   173  		cmds = append(cmds, LogProgressCmd("Running yum update"))
   174  		cmds = append(cmds, "package_manager_loop "+cfg.paccmder.UpdateCmd())
   175  	}
   176  	if cfg.SystemUpgrade() {
   177  		cmds = append(cmds, LogProgressCmd("Running yum upgrade"))
   178  		cmds = append(cmds, "package_manager_loop "+cfg.paccmder.UpgradeCmd())
   179  	}
   180  
   181  	pkgs := cfg.Packages()
   182  	if len(pkgs) > 0 {
   183  		cmds = append([]string{LogProgressCmd(fmt.Sprintf("Installing %s", strings.Join(pkgs, ", ")))}, cmds...)
   184  	}
   185  	for _, pkg := range pkgs {
   186  		cmds = append(cmds, "package_manager_loop "+cfg.paccmder.InstallCmd(pkg))
   187  	}
   188  	return cmds, nil
   189  }
   190  
   191  // AddPackageCommands is defined on the AdvancedPackagingConfig interface.
   192  func (cfg *centOSCloudConfig) AddPackageCommands(
   193  	packageProxySettings proxy.Settings,
   194  	packageMirror string,
   195  	addUpdateScripts bool,
   196  	addUpgradeScripts bool,
   197  ) {
   198  	addPackageCommandsCommon(
   199  		cfg,
   200  		packageProxySettings,
   201  		packageMirror,
   202  		addUpdateScripts,
   203  		addUpgradeScripts,
   204  		cfg.series,
   205  	)
   206  }
   207  
   208  // addRequiredPackages is defined on the AdvancedPackagingConfig interface.
   209  func (cfg *centOSCloudConfig) addRequiredPackages() {
   210  	packages := []string{
   211  		"curl",
   212  		"bridge-utils",
   213  		"cloud-utils",
   214  		"nmap-ncat",
   215  		"tmux",
   216  	}
   217  	if featureflag.Enabled(feature.DeveloperMode) {
   218  		packages = append(packages, "socat")
   219  	}
   220  
   221  	// The required packages need to come from the correct repo.
   222  	// For CentOS 7, this requires an rpm cloud archive be up.
   223  	// In the event of the addition of such a repository, its addition should
   224  	// happen in the utils/packaging/config package whilst leaving the below
   225  	// code untouched.
   226  	for _, pack := range packages {
   227  		if config.SeriesRequiresCloudArchiveTools(cfg.series) && cfg.pacconfer.IsCloudArchivePackage(pack) {
   228  			cfg.AddPackage(strings.Join(cfg.pacconfer.ApplyCloudArchiveTarget(pack), " "))
   229  		} else {
   230  			cfg.AddPackage(pack)
   231  		}
   232  	}
   233  }
   234  
   235  //TODO(bogdanteleaga, aznashwan): On ubuntu when we render the conf as yaml we
   236  //have apt_proxy and when we render it as bash we use the equivalent of this.
   237  //However on centOS even when rendering the YAML we use a helper function
   238  //addPackageProxyCmds. Research if calling the same is fine.
   239  func (cfg *centOSCloudConfig) updateProxySettings(proxySettings proxy.Settings) {
   240  }