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  }