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