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  }