github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cloudconfig/cloudinit/cloudinit.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 "strings" 9 10 "github.com/juju/utils/packaging/commands" 11 "github.com/juju/utils/packaging/config" 12 "github.com/juju/utils/shell" 13 14 "github.com/juju/juju/utils/ssh" 15 ) 16 17 // cloudConfig represents a set of cloud-init configuration options. 18 type cloudConfig struct { 19 // series is the series for which this cloudConfig is made for. 20 series string 21 22 // paccmder is the PackageCommander for this cloudConfig. 23 paccmder commands.PackageCommander 24 25 // pacconfer is the PackagingConfigurer for this cloudConfig. 26 pacconfer config.PackagingConfigurer 27 28 // renderer is the shell Renderer for this cloudConfig. 29 renderer shell.Renderer 30 31 // attrs is the map of options set on this cloudConfig. 32 // main attributes used in the options map and their corresponding types: 33 // 34 // user string 35 // package_update bool 36 // package_upgrade bool 37 // packages []string 38 // runcmd []string 39 // bootcmd []string 40 // disable_ec2_metadata bool 41 // final_message string 42 // locale string 43 // mounts [][]string 44 // output map[OutputKind]string 45 // shh_keys map[SSHKeyType]string 46 // ssh_authorized_keys []string 47 // disable_root bool 48 // 49 // used only for Ubuntu but implemented as runcmds on CentOS: 50 // apt_proxy string 51 // apt_mirror string/bool 52 // apt_sources []*packaging.Source 53 // 54 // instead, the following corresponding options are used temporarily, 55 // but are translated to runcmds and removed right before rendering: 56 // package_proxy 57 // package_mirror 58 // package_sources 59 // package_preferences 60 // 61 // old TODO's: 62 // byobu 63 // grub_dpkg 64 // mcollective 65 // phone_home 66 // puppet 67 // resizefs 68 // rightscale_userdata 69 // scripts_per_boot 70 // scripts_per_instance 71 // scripts_per_once 72 // scripts_user 73 // set_hostname 74 // set_passwords 75 // ssh_import_id 76 // timezone 77 // update_etc_hosts 78 // update_hostname 79 attrs map[string]interface{} 80 } 81 82 // getPackageCommander is defined on the AdvancedPackagingConfig interface. 83 func (cfg *cloudConfig) getPackageCommander() commands.PackageCommander { 84 return cfg.paccmder 85 } 86 87 // getPackagingConfigurer is defined on the AdvancedPackagingConfig interface. 88 func (cfg *cloudConfig) getPackagingConfigurer() config.PackagingConfigurer { 89 return cfg.pacconfer 90 } 91 92 // GetSeries is defined on the CloudConfig interface. 93 func (cfg *cloudConfig) GetSeries() string { 94 return cfg.series 95 } 96 97 // SetAttr is defined on the CloudConfig interface. 98 func (cfg *cloudConfig) SetAttr(name string, value interface{}) { 99 cfg.attrs[name] = value 100 } 101 102 // UnsetAttr is defined on the CloudConfig interface. 103 func (cfg *cloudConfig) UnsetAttr(name string) { 104 delete(cfg.attrs, name) 105 } 106 107 // SetUser is defined on the UserConfig interface. 108 func (cfg *cloudConfig) SetUser(user string) { 109 cfg.SetAttr("user", user) 110 } 111 112 // UnsetUser is defined on the UserConfig interface. 113 func (cfg *cloudConfig) UnsetUser() { 114 cfg.UnsetAttr("user") 115 } 116 117 // User is defined on the UserConfig interface. 118 func (cfg *cloudConfig) User() string { 119 user, _ := cfg.attrs["user"].(string) 120 return user 121 } 122 123 // SetSystemUpdate is defined on the SystemUpdateConfig interface. 124 func (cfg *cloudConfig) SetSystemUpdate(yes bool) { 125 cfg.SetAttr("package_update", yes) 126 } 127 128 // UnsetSystemUpdate is defined on the SystemUpdateConfig interface. 129 func (cfg *cloudConfig) UnsetSystemUpdate() { 130 cfg.UnsetAttr("package_update") 131 } 132 133 // SystemUpdate is defined on the SystemUpdateConfig interface. 134 func (cfg *cloudConfig) SystemUpdate() bool { 135 update, _ := cfg.attrs["package_update"].(bool) 136 return update 137 } 138 139 // SetSystemUpgrade is defined on the SystemUpgradeConfig interface. 140 func (cfg *cloudConfig) SetSystemUpgrade(yes bool) { 141 cfg.SetAttr("package_upgrade", yes) 142 } 143 144 // UnsetSystemUpgrade is defined on the SystemUpgradeConfig interface. 145 func (cfg *cloudConfig) UnsetSystemUpgrade() { 146 cfg.UnsetAttr("package_upgrade") 147 } 148 149 // SystemUpgrade is defined on the SystemUpgradeConfig interface. 150 func (cfg *cloudConfig) SystemUpgrade() bool { 151 upgrade, _ := cfg.attrs["package_upgrade"].(bool) 152 return upgrade 153 } 154 155 // AddPackage is defined on the PackagingConfig interface. 156 func (cfg *cloudConfig) AddPackage(pack string) { 157 cfg.attrs["packages"] = append(cfg.Packages(), pack) 158 } 159 160 // RemovePackage is defined on the PackagingConfig interface. 161 func (cfg *cloudConfig) RemovePackage(pack string) { 162 cfg.attrs["packages"] = removeStringFromSlice(cfg.Packages(), pack) 163 } 164 165 // Packages is defined on the PackagingConfig interface. 166 func (cfg *cloudConfig) Packages() []string { 167 packs, _ := cfg.attrs["packages"].([]string) 168 return packs 169 } 170 171 // AddRunCmd is defined on the RunCmdsConfig interface. 172 func (cfg *cloudConfig) AddRunCmd(args ...string) { 173 cfg.attrs["runcmd"] = append(cfg.RunCmds(), strings.Join(args, " ")) 174 } 175 176 // AddScripts is defined on the RunCmdsConfig interface. 177 func (cfg *cloudConfig) AddScripts(script ...string) { 178 for _, line := range script { 179 cfg.AddRunCmd(line) 180 } 181 } 182 183 // RemoveRunCmd is defined on the RunCmdsConfig interface. 184 func (cfg *cloudConfig) RemoveRunCmd(cmd string) { 185 cfg.attrs["runcmd"] = removeStringFromSlice(cfg.RunCmds(), cmd) 186 } 187 188 // RunCmds is defined on the RunCmdsConfig interface. 189 func (cfg *cloudConfig) RunCmds() []string { 190 cmds, _ := cfg.attrs["runcmd"].([]string) 191 return cmds 192 } 193 194 // AddBootCmd is defined on the BootCmdsConfig interface. 195 func (cfg *cloudConfig) AddBootCmd(args ...string) { 196 cfg.attrs["bootcmd"] = append(cfg.BootCmds(), strings.Join(args, " ")) 197 } 198 199 // RemoveBootCmd is defined on the BootCmdsConfig interface. 200 func (cfg *cloudConfig) RemoveBootCmd(cmd string) { 201 cfg.attrs["bootcmd"] = removeStringFromSlice(cfg.BootCmds(), cmd) 202 } 203 204 // BootCmds is defined on the BootCmdsConfig interface. 205 func (cfg *cloudConfig) BootCmds() []string { 206 cmds, _ := cfg.attrs["bootcmd"].([]string) 207 return cmds 208 } 209 210 // SetDisableEC2Metadata is defined on the EC2MetadataConfig interface. 211 func (cfg *cloudConfig) SetDisableEC2Metadata(set bool) { 212 cfg.SetAttr("disable_ec2_metadata", set) 213 } 214 215 // UnsetDisableEC2Metadata is defined on the EC2MetadataConfig interface. 216 func (cfg *cloudConfig) UnsetDisableEC2Metadata() { 217 cfg.UnsetAttr("disable_ec2_metadata") 218 } 219 220 // DisableEC2Metadata is defined on the EC2MetadataConfig interface. 221 func (cfg *cloudConfig) DisableEC2Metadata() bool { 222 disEC2, _ := cfg.attrs["disable_ec2_metadata"].(bool) 223 return disEC2 224 } 225 226 // SetFinalMessage is defined on the FinalMessageConfig interface. 227 func (cfg *cloudConfig) SetFinalMessage(message string) { 228 cfg.SetAttr("final_message", message) 229 } 230 231 // UnsetFinalMessage is defined on the FinalMessageConfig interface. 232 func (cfg *cloudConfig) UnsetFinalMessage() { 233 cfg.UnsetAttr("final_message") 234 } 235 236 // FinalMessage is defined on the FinalMessageConfig interface. 237 func (cfg *cloudConfig) FinalMessage() string { 238 message, _ := cfg.attrs["final_message"].(string) 239 return message 240 } 241 242 // SetLocale is defined on the LocaleConfig interface. 243 func (cfg *cloudConfig) SetLocale(locale string) { 244 cfg.SetAttr("locale", locale) 245 } 246 247 // UnsetLocale is defined on the LocaleConfig interface. 248 func (cfg *cloudConfig) UnsetLocale() { 249 cfg.UnsetAttr("locale") 250 } 251 252 // Locale is defined on the LocaleConfig interface. 253 func (cfg *cloudConfig) Locale() string { 254 locale, _ := cfg.attrs["locale"].(string) 255 return locale 256 } 257 258 // AddMount adds takes arguments for installing a mount point in /etc/fstab 259 // The options are of the order and format specific to fstab entries: 260 // <device> <mountpoint> <filesystem> <options> <backup setting> <fsck priority> 261 func (cfg *cloudConfig) AddMount(mount ...string) { 262 mounts, _ := cfg.attrs["mounts"].([][]string) 263 cfg.SetAttr("mounts", append(mounts, mount)) 264 } 265 266 // SetOutput is defined on the OutputConfig interface. 267 func (cfg *cloudConfig) SetOutput(kind OutputKind, stdout, stderr string) { 268 out, _ := cfg.attrs["output"].(map[string]interface{}) 269 if out == nil { 270 out = make(map[string]interface{}) 271 } 272 273 if stderr == "" { 274 out[string(kind)] = stdout 275 } else { 276 out[string(kind)] = []string{stdout, stderr} 277 } 278 279 cfg.SetAttr("output", out) 280 } 281 282 // Output is defined on the OutputConfig interface. 283 func (cfg *cloudConfig) Output(kind OutputKind) (stdout, stderr string) { 284 if out, ok := cfg.attrs["output"].(map[string]interface{}); ok { 285 switch out := out[string(kind)].(type) { 286 case string: 287 stdout = out 288 case []string: 289 stdout, stderr = out[0], out[1] 290 } 291 } 292 293 return stdout, stderr 294 } 295 296 // AddSSHKey is defined on the SSHKeyConfi interface. 297 func (cfg *cloudConfig) AddSSHKey(keyType SSHKeyType, key string) { 298 keys, _ := cfg.attrs["ssh_keys"].(map[SSHKeyType]string) 299 if keys == nil { 300 keys = make(map[SSHKeyType]string) 301 cfg.SetAttr("ssh_keys", keys) 302 } 303 304 keys[keyType] = key 305 } 306 307 // AddSSHAuthorizedKeys is defined on the SSHKeysConfig interface. 308 func (cfg *cloudConfig) AddSSHAuthorizedKeys(rawKeys string) { 309 cfgKeys, _ := cfg.attrs["ssh_authorized_keys"].([]string) 310 keys := ssh.SplitAuthorisedKeys(rawKeys) 311 for _, key := range keys { 312 // ensure our keys have "Juju:" prepended in order to differenciate 313 // Juju-managed keys and externally added ones 314 jujuKey := ssh.EnsureJujuComment(key) 315 316 cfgKeys = append(cfgKeys, jujuKey) 317 } 318 cfg.SetAttr("ssh_authorized_keys", cfgKeys) 319 } 320 321 // SetDisableRoot is defined on the RootUserConfig interface. 322 func (cfg *cloudConfig) SetDisableRoot(disable bool) { 323 cfg.SetAttr("disable_root", disable) 324 } 325 326 // UnsetDisableRoot is defined on the RootUserConfig interface. 327 func (cfg *cloudConfig) UnsetDisableRoot() { 328 cfg.UnsetAttr("disable_root") 329 } 330 331 // DisableRoot is defined on the RootUserConfig interface. 332 func (cfg *cloudConfig) DisableRoot() bool { 333 disable, _ := cfg.attrs["disable_root"].(bool) 334 return disable 335 } 336 337 // AddRunTextFile is defined on the WrittenFilesConfig interface. 338 func (cfg *cloudConfig) AddRunTextFile(filename, contents string, perm uint) { 339 cfg.AddScripts(addFileCmds(filename, []byte(contents), perm, false)...) 340 } 341 342 // AddBootTextFile is defined on the WrittenFilesConfig interface. 343 func (cfg *cloudConfig) AddBootTextFile(filename, contents string, perm uint) { 344 for _, cmd := range addFileCmds(filename, []byte(contents), perm, false) { 345 cfg.AddBootCmd(cmd) 346 } 347 } 348 349 // AddRunBinaryFile is defined on the WrittenFilesConfig interface. 350 func (cfg *cloudConfig) AddRunBinaryFile(filename string, data []byte, mode uint) { 351 cfg.AddScripts(addFileCmds(filename, data, mode, true)...) 352 } 353 354 // ShellRenderer is defined on the RenderConfig interface. 355 func (cfg *cloudConfig) ShellRenderer() shell.Renderer { 356 return cfg.renderer 357 } 358 359 // RequiresCloudArchiveCloudTools is defined on the AdvancedPackagingConfig 360 // interface. 361 func (cfg *cloudConfig) RequiresCloudArchiveCloudTools() bool { 362 return config.SeriesRequiresCloudArchiveTools(cfg.series) 363 }