Esempio n. 1
0
// writeFiles persists the given files to the system.
func (imp *Implementation) writeFiles(files []cloudconfig.WriteFile) {
	for _, f := range files {
		p, err := strconv.Atoi(f.Permissions)
		if err != nil {
			flog.Error("Failed to convert permissions",
				flog.Fields{
					Event: "strconv.Atoi",
					Error: err,
				},
				flog.Details{
					"file":        f.Path,
					"permissions": f.Permissions,
				},
			)
			continue
		}

		perms := os.FileMode(p)

		err = file.New(f.Path, file.Permissions(perms), file.Contents(f.Content))
		if err != nil {
			flog.Error("Failed to create file",
				flog.Fields{
					Event: "file.New",
					Error: err,
				},
				flog.Details{
					"file": f.Path,
				},
			)
		}
	}
}
Esempio n. 2
0
// ConsumeMetadata uses the given userdata to contextualize the distribution implementation.
func (imp *Implementation) ConsumeMetadata(m *metadata.Digest) error {
	flog.Info("Consuming meta-data",
		flog.Fields{
			Event: "distro.Implementation.ConsumeMetadata",
		},
	)

	if err := imp.setHostname(m.Hostname); err != nil {
		flog.Error("Failed to set hostname",
			flog.Fields{
				Event: "distro.Implementation.setHostname",
			},
			flog.Details{
				"name": m.Hostname,
			},
		)
		return err
	}

	imp.consumeSSHKeys(m.SSHKeys)

	flog.Info("Finished consuming meta-data",
		flog.Fields{
			Event: "distro.Implementation.ConsumeUserdata",
		},
	)

	return nil
}
Esempio n. 3
0
// consumeCommands executes the given command and it's arguments.
func (imp *Implementation) consumeCommands(commands [][]string) {
	for _, cmd := range commands {
		flog.Debug("Executing command",
			flog.Fields{
				Event: "distro.Implementation.consumeCommands",
			},
			flog.Details{
				"command": cmd,
			},
		)

		out, err := imp.Execute(cmd[0], cmd[1:]...)
		if err != nil {
			flog.Error("Failed to execute command",
				flog.Fields{
					Event: "distro.Implementation.Execute",
					Error: err,
				},
				flog.Details{
					"command": cmd,
				},
			)
		}

		flog.Debug("Executed command",
			flog.Fields{
				Event: "distro.Implementation.consumeCommands",
			},
			flog.Details{
				"command": cmd,
				"output":  out,
			},
		)
	}
}
Esempio n. 4
0
// consumeScripts executes the given name/script content pairs.
func (imp *Implementation) consumeScripts(scripts map[string]string) {
	for name, content := range scripts {
		flog.Info("Executing script",
			flog.Fields{
				Event: "distro.consumeScripts",
			},
			flog.Details{
				"name": name,
			},
		)

		if err := imp.executeScript(content); err != nil {
			flog.Error("Failed to execute script",
				flog.Fields{
					Event: "distro.executeScript",
				},
				flog.Details{
					"name": name,
				},
				flog.DebugFields{
					"content": content,
				},
			)
		}
	}
}
Esempio n. 5
0
// consumeSSHKeys authorizes the given SSH keys for the user.
func (imp *Implementation) consumeSSHKeys(userKeys map[string][]ssh.Key) {
	for userName, sshKeys := range userKeys {
		flog.Info("Authorizing SSH keys",
			flog.Fields{
				Event: "distro.consumeSSHKeys",
			},
			flog.Details{
				"user": userName,
			},
		)

		usr, err := nss.GetUser(userName)
		if err != nil {
			flog.Error("Failed to retrieve user NSS entry",
				flog.Fields{
					Event: "nss.GetUser",
					Error: err,
				},
				flog.Details{
					"user": userName,
				},
			)
			continue
		}

		if err := ssh.AuthorizeKeysFor(usr, sshKeys); err != nil {
			flog.Error("Failed to authorize SSH keys for user",
				flog.Fields{
					Event: "ssh.AuthorizeKeysFor",
					Error: err,
				},
				flog.Details{
					"user": userName,
				},
				flog.DebugFields{
					"SSHKeys": sshKeys,
				},
			)
		}
	}
}
Esempio n. 6
0
// consumeCloudConfig parses the given cloud config file contents and
// consumes the parsed directives.
func (imp *Implementation) consumeCloudConfig(contents string) error {
	conf, err := cloudconfig.Parse(strutil.ToReadCloser(contents))
	if err != nil {
		flog.Error("Failed to parse cloud config file",
			flog.Fields{
				Event: "cloudconfig.Parse",
				Error: err,
			},
		)

		return err
	}

	flog.Debug("Persisting files",
		flog.Fields{
			Event: "distro.Implementation.consumeCloudConfig",
		},
	)

	imp.writeFiles(conf.Files)

	imp.consumeCommands(conf.Commands)

	for grpName, _ := range conf.Groups {
		flog.Info("Creating user group",
			flog.Fields{
				Event: "distro.consumeCloudConfig",
			},
			flog.Details{
				"group": grpName,
			},
		)

		newGrp := identity.Group{
			Name: grpName,
		}

		if err := imp.ID.CreateGroup(newGrp); err != nil {
			flog.Error("Failed to create a user group",
				flog.Fields{
					Event: "identityManager.CreateGroup",
					Error: err,
				},
				flog.Details{
					"group": grpName,
				},
			)
		}
	}

	for _, usr := range conf.Users {
		flog.Info("Creating user",
			flog.Fields{
				Event: "distro.consumeCloudConfig",
			},
			flog.Details{
				"user": usr.Name,
			},
		)

		if err := imp.ID.CreateUser(usr); err != nil {
			flog.Error("Failed to create a user",
				flog.Fields{
					Event: "identityManager.CreateUser",
					Error: err,
				},
				flog.Details{
					"user": usr.Name,
				},
			)
		}
	}

	for grpName, usrNames := range conf.Groups {
		for _, usrName := range usrNames {
			flog.Info("Adding user to group",
				flog.Fields{
					Event: "distro.consumeCloudConfig",
				},
				flog.Details{
					"user":  usrName,
					"group": grpName,
				},
			)

			if err := imp.ID.AddUserToGroup(usrName, grpName); err != nil {
				flog.Error("Failed to add user to group",
					flog.Fields{
						Event: "identityManager.AddUserToGroup",
						Error: err,
					},
					flog.Details{
						"user":  usrName,
						"group": grpName,
					},
				)
			}
		}
	}

	imp.consumeSSHKeys(conf.AuthorizedKeys)

	return err
}
Esempio n. 7
0
// ConsumeUserdata uses the given userdata to contextualize the distribution implementation.
func (imp *Implementation) ConsumeUserdata(u userdata.Map) error {
	// TODO(tmrts): Store unused user-data in files?
	// TODO(tmrts): Execute scripts in rc.local or a similar level
	flog.Info("Consuming user-data",
		flog.Fields{
			Event: "distro.ConsumeUserdata",
		},
	)

	// TODO(tmrts): Use only scripts with 'startup', 'shutdown', 'user-data'.
	scripts := u.Scripts()
	flog.Info("Searched for script files",
		flog.Fields{
			Event: "userdata.Map.Scripts",
		},
		flog.Details{
			"count": len(scripts),
		},
	)

	imp.consumeScripts(scripts)

	confs := u.CloudConfigs()
	flog.Info("Searched for cloud-config files",
		flog.Fields{
			Event: "userdata.Map.CloudConfigs",
		},
		flog.Details{
			"count": len(confs),
		},
	)

	for name, content := range confs {
		flog.Info("Consuming user-data file",
			flog.Fields{
				Event: "distro.ConsumeUserdata",
			},
			flog.Details{
				"name": name,
			},
		)

		err := imp.consumeCloudConfig(content)
		if err != nil {
			flog.Error("Failed to consume cloud-config file",
				flog.Fields{
					Event: "distro.consumeCloudConfig",
				},
				flog.Details{
					"name": name,
				},
				flog.DebugFields{
					"content": content,
				},
			)
			return err
		}
	}

	flog.Info("Finished consuming user-data",
		flog.Fields{
			Event: "distro.Implementation.ConsumeUserdata",
		},
	)

	return nil
}