Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Truncate the file to avoid messing up the config file #216

Merged
merged 3 commits into from
Mar 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ecs-cli/modules/config/readwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ func (rdwr *IniReadWriter) Save(dest *Destination) error {
// Open the file, optionally creating it with our desired permissions.
// This will let us pass it (as io.Writer) to go-ini but let us control the file.
configFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, configFileMode)

// Truncate the file in case the earlier contents are longer than the new
// contents, so there will not be any trash at the end of the file
configFile.Truncate(0)

if err != nil {
logrus.Errorf("Unable to open/create %s with mode %s", path, configFileMode)
return err
Expand Down
167 changes: 84 additions & 83 deletions ecs-cli/modules/config/readwriter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ import (
"io/ioutil"
"os"
"testing"

"github.com/stretchr/testify/assert"
)

const testClusterName = "test-cluster"
const (
testClusterName = "test-cluster"
testAWSProfile = "aws-profile"
)

func newMockDestination() (*Destination, error) {
tmpPath, err := ioutil.TempDir(os.TempDir(), "ecs-cli-test-")
Expand All @@ -37,120 +42,97 @@ func newMockDestination() (*Destination, error) {

func setupParser(t *testing.T, dest *Destination, shouldBeInitialized bool) *IniReadWriter {
iniCfg, err := newIniConfig(dest)
if err != nil {
t.Fatal("Error creating config ini", err)
}
assert.NoError(t, err, "Error creating config ini")

parser := &IniReadWriter{Destination: dest, cfg: iniCfg}

// Test when unitialized.
initialized, err := parser.IsInitialized()
if err != nil {
t.Errorf("Error getting if initialized from ini", err)
}

if shouldBeInitialized != initialized {
t.Error("Unexpected state during parser initialization. Expected initialized to be [%s] but found [%s]", shouldBeInitialized, initialized)
}
assert.NoError(t, err, "Error getting if initialized from ini")
assert.Equal(t, shouldBeInitialized, initialized, "Unexpected state during parser initialization.")

return parser
}

func createConfig(t *testing.T, parser *IniReadWriter, dest *Destination) {
func saveConfigWithCluster(t *testing.T, parser *IniReadWriter, dest *Destination) {
saveConfig(t, parser, dest, &SectionKeys{Cluster: testClusterName})
}

func saveConfig(t *testing.T, parser *IniReadWriter, dest *Destination, sectionKeys *SectionKeys) {
// Create a new config file
newConfig := &CliConfig{&SectionKeys{Cluster: testClusterName}}
newConfig := &CliConfig{sectionKeys}
err := parser.ReadFrom(newConfig)
if err != nil {
t.Fatalf("Could not create config from struct", err)
}
assert.NoError(t, err, "Could not create config from struct")

err = parser.Save(dest)
if err != nil {
t.Fatalf("Could not save config file", err)
}
assert.NoError(t, err, "Could not save config file")
}

func TestConfigPermissions(t *testing.T) {
dest, err := newMockDestination()
if err != nil {
t.Fatal("Error creating mock config destination:", err)
}
assert.NoError(t, err, "Error creating mock config destination")

parser := setupParser(t, dest, false)

err = os.MkdirAll(dest.Path, *dest.Mode)
if err != nil {
t.Fatalf("Could not create config directory: ", err)
}
assert.NoError(t, err, "Could not create config directory")

defer os.RemoveAll(dest.Path)

// Create config file and confirm it has expected initial permissions
createConfig(t, parser, dest)
saveConfigWithCluster(t, parser, dest)

path := configPath(dest)
confirmConfigMode(t, path, configFileMode)

// Now set the config mode to something bad
badMode := os.FileMode(0777)
err = os.Chmod(path, badMode)
if err != nil {
t.Fatalf("Unable to change mode of new config %v", path)
}
assert.NoError(t, err, "Unable to change mode of new config %v", path)

confirmConfigMode(t, path, badMode)

// Save the config and confirm it's fixed again
err = parser.Save(dest)
if err != nil {
t.Fatalf("Unable to save to new config %v", path)
}
assert.NoError(t, err, "Unable to save to new config %v", path)

confirmConfigMode(t, path, configFileMode)
}

func confirmConfigMode(t *testing.T, path string, expected os.FileMode) {
info, err := os.Stat(path)
if err != nil {
t.Fatalf("Unable to stat config file %s", path)
}
assert.NoError(t, err, "Unable to stat config file %s", path)

mode := info.Mode()
if mode != expected {
t.Fatalf("Mode of config %v not expected %v", mode, expected)
}
assert.Equal(t, expected, mode, "Made of config does not match")

}

func TestNewConfigReadWriter(t *testing.T) {
dest, err := newMockDestination()
if err != nil {
t.Fatal("Error creating mock config destination:", err)
}
assert.NoError(t, err, "Error creating mock config destination")

parser := setupParser(t, dest, false)

err = os.MkdirAll(dest.Path, *dest.Mode)
if err != nil {
t.Fatalf("Could not create config directory: ", err)
}
assert.NoError(t, err, "Could not create config directory")

defer os.RemoveAll(dest.Path)

createConfig(t, parser, dest)
saveConfigWithCluster(t, parser, dest)

// Reinitialize from the written file.
parser = setupParser(t, dest, true)

readConfig, err := parser.GetConfig()
if err != nil {
t.Errorf("Error reading config:", err)
}

if testClusterName != readConfig.Cluster {
t.Errorf("Cluster name mismatch in config. Expected [%s] Got [%s]", testClusterName, readConfig.Cluster)
}
if !parser.IsKeyPresent(ecsSectionKey, composeProjectNamePrefixKey) || readConfig.ComposeProjectNamePrefix != "" {
t.Errorf("Compose Project prefix name mismatch in config. Expected empty string Got [%s]", readConfig.ComposeProjectNamePrefix)
}
if !parser.IsKeyPresent(ecsSectionKey, composeServiceNamePrefixKey) || readConfig.ComposeServiceNamePrefix != "" {
t.Errorf("Compose service name prefix mismatch in config. Expected empty string Got [%s]", readConfig.ComposeServiceNamePrefix)
}
if !parser.IsKeyPresent(ecsSectionKey, cfnStackNamePrefixKey) || readConfig.CFNStackNamePrefix != "" {
t.Errorf("CFNStackNamePrefix mismatch in config. Expected empty string Got [%s]", readConfig.CFNStackNamePrefix)
}
assert.NoError(t, err, "Error reading config")
assert.Equal(t, testClusterName, readConfig.Cluster, "Cluster name mismatch in config.")
assert.True(t, parser.IsKeyPresent(ecsSectionKey, composeProjectNamePrefixKey), "Compose project prefix name should exist in config.")
assert.Empty(t, readConfig.ComposeProjectNamePrefix, "Compose project prefix name should be empty.")
assert.True(t, parser.IsKeyPresent(ecsSectionKey, composeServiceNamePrefixKey), "Compose service name prefix should exist in config.")
assert.Empty(t, readConfig.ComposeServiceNamePrefix, "Compose service prefix name should be empty.")
assert.True(t, parser.IsKeyPresent(ecsSectionKey, cfnStackNamePrefixKey), "CFNStackNamePrefix should exist in config.")
assert.Empty(t, readConfig.CFNStackNamePrefix, "CFNStackNamePrefix should be empty.")
}

func TestMissingPrefixes(t *testing.T) {
Expand All @@ -162,33 +144,52 @@ aws_access_key_id =
aws_secret_access_key =
`
dest, err := newMockDestination()
if err != nil {
t.Fatal("Error creating mock config destination:", err)
}
assert.NoError(t, err, "Error creating mock config destination")

err = os.MkdirAll(dest.Path, *dest.Mode)
if err != nil {
t.Fatalf("Could not create config directory: ", err)
}
assert.NoError(t, err, "Could not create config directory")

defer os.RemoveAll(dest.Path)

if err = ioutil.WriteFile(dest.Path+"/"+configFileName, []byte(configContentsNoPrefixes), *dest.Mode); err != nil {
t.Fatal(err)
}
err = ioutil.WriteFile(dest.Path+"/"+configFileName, []byte(configContentsNoPrefixes), *dest.Mode)
assert.NoError(t, err)

parser := setupParser(t, dest, true)
readConfig, err := parser.GetConfig()
if err != nil {
t.Errorf("Error reading config:", err)
}
_, err = parser.GetConfig()
assert.NoError(t, err, "Error reading config")
assert.False(t, parser.IsKeyPresent(ecsSectionKey, cfnStackNamePrefixKey), "CFNStackNamePrefix should not exist in config")
assert.False(t, parser.IsKeyPresent(ecsSectionKey, composeServiceNamePrefixKey), "Compose service name prefix should not exist in config")
assert.False(t, parser.IsKeyPresent(ecsSectionKey, composeProjectNamePrefixKey), "Compose project name prefix should not exist in config")
}

if parser.IsKeyPresent(ecsSectionKey, cfnStackNamePrefixKey) {
t.Errorf("Expected key [%s] not to be present. Got value=[%s]", cfnStackNamePrefixKey, readConfig.CFNStackNamePrefix)
}
if parser.IsKeyPresent(ecsSectionKey, composeServiceNamePrefixKey) {
t.Errorf("Expected key [%s] not to be present. Got value=[%s]", composeServiceNamePrefixKey, readConfig.ComposeServiceNamePrefix)
}
if parser.IsKeyPresent(ecsSectionKey, composeProjectNamePrefixKey) {
t.Errorf("Expected key [%s] not to be present. Got value=[%s]", composeProjectNamePrefixKey, readConfig.ComposeProjectNamePrefix)
}
func TestConfigFileTruncation(t *testing.T) {
configContents := `[ecs]
cluster = very-long-cluster-name
aws_profile = some-long-profile
region = us-west-2
aws_access_key_id =
aws_secret_access_key =
compose-project-name-prefix = ecscompose-
compose-service-name-prefix = ecscompose-service-
cfn-stack-name-prefix = amazon-ecs-cli-setup-
`
dest, err := newMockDestination()
assert.NoError(t, err, "Error creating mock config destination")

parser := setupParser(t, dest, false)

err = os.MkdirAll(dest.Path, *dest.Mode)
assert.NoError(t, err, "Could not create config directory")

defer os.RemoveAll(dest.Path)

// Save config for the first time
err = ioutil.WriteFile(dest.Path+"/"+configFileName, []byte(configContents), *dest.Mode)
assert.NoError(t, err)

// Save config with shorter cluster name
saveConfigWithCluster(t, parser, dest)

_, err = newIniConfig(dest)
assert.NoError(t, err)
}