Merge pull request #5 from bcwaldon/write_files

Implement write_files feature
This commit is contained in:
Brian Waldon 2014-03-11 20:56:43 -07:00
commit 6803aed2dd
4 changed files with 173 additions and 1 deletions

View File

@ -10,7 +10,11 @@ const DefaultSSHKeyName = "coreos-cloudinit"
type CloudConfig struct { type CloudConfig struct {
SSH_Authorized_Keys []string SSH_Authorized_Keys []string
Coreos struct{Etcd struct{ Discovery_URL string }; Fleet struct{ Autostart bool } } Coreos struct {
Etcd struct{ Discovery_URL string }
Fleet struct{ Autostart bool }
}
Write_Files []WriteFile
} }
func NewCloudConfig(contents []byte) (*CloudConfig, error) { func NewCloudConfig(contents []byte) (*CloudConfig, error) {
@ -38,6 +42,15 @@ func ApplyCloudConfig(cfg CloudConfig, sshKeyName string) error {
} }
} }
if len(cfg.Write_Files) > 0 {
for _, file := range cfg.Write_Files {
if err := ProcessWriteFile("/", &file); err != nil {
return err
}
log.Printf("Wrote file %s to filesystem", file.Path)
}
}
if cfg.Coreos.Etcd.Discovery_URL != "" { if cfg.Coreos.Etcd.Discovery_URL != "" {
err := PersistEtcdDiscoveryURL(cfg.Coreos.Etcd.Discovery_URL) err := PersistEtcdDiscoveryURL(cfg.Coreos.Etcd.Discovery_URL)
if err == nil { if err == nil {

View File

@ -23,6 +23,10 @@ func TestCloudConfigEmpty(t *testing.T) {
if cfg.Coreos.Fleet.Autostart { if cfg.Coreos.Fleet.Autostart {
t.Error("Expected AutostartFleet not to be defined") t.Error("Expected AutostartFleet not to be defined")
} }
if len(cfg.Write_Files) != 0 {
t.Error("Expected zero Write_Files")
}
} }
// Assert that the parsing of a cloud config file "generally works" // Assert that the parsing of a cloud config file "generally works"
@ -36,6 +40,13 @@ coreos:
ssh_authorized_keys: ssh_authorized_keys:
- foobar - foobar
- foobaz - foobaz
write_files:
- content: |
penny
elroy
path: /etc/dogepack.conf
permissions: '0644'
owner: root:dogepack
`) `)
cfg, err := NewCloudConfig(contents) cfg, err := NewCloudConfig(contents)
if err != nil { if err != nil {
@ -58,6 +69,27 @@ ssh_authorized_keys:
if !cfg.Coreos.Fleet.Autostart { if !cfg.Coreos.Fleet.Autostart {
t.Error("Expected AutostartFleet to be true") t.Error("Expected AutostartFleet to be true")
} }
if len(cfg.Write_Files) != 1 {
t.Error("Failed to parse correct number of write_files")
} else {
wf := cfg.Write_Files[0]
if wf.Content != "penny\nelroy\n" {
t.Errorf("WriteFile has incorrect contents '%s'", wf.Content)
}
if wf.Encoding != "" {
t.Errorf("WriteFile has incorrect encoding %s", wf.Encoding)
}
if wf.Permissions != "0644" {
t.Errorf("WriteFile has incorrect permissions %s", wf.Permissions)
}
if wf.Path != "/etc/dogepack.conf" {
t.Errorf("WriteFile has incorrect path %s", wf.Path)
}
if wf.Owner != "root:dogepack" {
t.Errorf("WriteFile has incorrect owner %s", wf.Owner)
}
}
} }
// Assert that our interface conversion doesn't panic // Assert that our interface conversion doesn't panic

46
cloudinit/write_file.go Normal file
View File

@ -0,0 +1,46 @@
package cloudinit
import (
"errors"
"io/ioutil"
"os"
"os/exec"
"path"
"strconv"
)
type WriteFile struct {
Encoding string
Content string
Owner string
Path string
Permissions string
}
func ProcessWriteFile(base string, wf *WriteFile) error {
fullPath := path.Join(base, wf.Path)
if err := os.MkdirAll(path.Dir(fullPath), os.FileMode(0744)); err != nil {
return err
}
// Parse string representation of file mode as octal
perm, err := strconv.ParseInt(wf.Permissions, 8, 32)
if err != nil {
return errors.New("Unable to parse file permissions as octal integer")
}
if err := ioutil.WriteFile(fullPath, []byte(wf.Content), os.FileMode(perm)); err != nil {
return err
}
if wf.Owner != "" {
// We shell out since we don't have a way to look up unix groups natively
cmd := exec.Command("chown", wf.Owner, fullPath)
if err := cmd.Run(); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,81 @@
package cloudinit
import (
"io/ioutil"
"os"
"path"
"syscall"
"testing"
)
func TestWriteFileUnencodedContent(t *testing.T) {
wf := WriteFile{
Path: "/tmp/foo",
Content: "bar",
Permissions: "0644",
}
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
if err != nil {
t.Fatalf("Unable to create tempdir: %v", err)
}
defer syscall.Rmdir(dir)
if err := ProcessWriteFile(dir, &wf); err != nil {
t.Fatalf("Processing of WriteFile failed: %v", err)
}
fullPath := path.Join(dir, "tmp", "foo")
fi, err := os.Stat(fullPath)
if err != nil {
t.Fatalf("Unable to stat file: %v", err)
}
if fi.Mode() != os.FileMode(0644) {
t.Errorf("File has incorrect mode: %v", fi.Mode())
}
contents, err := ioutil.ReadFile(fullPath)
if err != nil {
t.Fatalf("Unable to read expected file: %v", err)
}
if string(contents) != "bar" {
t.Fatalf("File has incorrect contents")
}
}
func TestWriteFileInvalidPermission(t *testing.T) {
wf := WriteFile{
Path: "/tmp/foo",
Content: "bar",
Permissions: "pants",
}
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
if err != nil {
t.Fatalf("Unable to create tempdir: %v", err)
}
defer syscall.Rmdir(dir)
if err := ProcessWriteFile(dir, &wf); err == nil {
t.Fatalf("Expected error to be raised when writing file with invalid permission")
}
}
func TestWriteFileEncodedContent(t *testing.T) {
wf := WriteFile{
Path: "/tmp/foo",
Content: "",
Encoding: "base64",
}
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
if err != nil {
t.Fatalf("Unable to create tempdir: %v", err)
}
defer syscall.Rmdir(dir)
if err := ProcessWriteFile(dir, &wf); err == nil {
t.Fatalf("Expected error to be raised when writing file with encoding")
}
}