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