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 }