Skip to content

Commit

Permalink
Do not overwrite AWS config when sync fails (#569)
Browse files Browse the repository at this point in the history
* Do not overwrite AWS config when sync fails

Fix issue #386

* Add WriteOnSyncFailure option to repo sync
  • Loading branch information
sosheskaz committed Dec 14, 2023
1 parent 81dac1f commit dfa6ad4
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 9 deletions.
1 change: 1 addition & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ type Registry struct {
Priority *int `toml:"priority, omitempty"`
PrefixDuplicateProfiles bool `toml:"prefixDuplicateProfiles,omitempty"`
PrefixAllProfiles bool `toml:"prefixAllProfiles,omitempty"`
WriteOnSyncFailure bool `toml:"writeOnSyncFailure,omitempty"`
}

// NewDefaultConfig returns a config with OS specific defaults populated
Expand Down
3 changes: 3 additions & 0 deletions pkg/granted/registry/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var AddCommand = cli.Command{
&cli.StringFlag{Name: "ref", Hidden: true},
&cli.BoolFlag{Name: "prefix-all-profiles", Aliases: []string{"pap"}, Usage: "provide this flag if you want to append registry name to all profiles"},
&cli.BoolFlag{Name: "prefix-duplicate-profiles", Aliases: []string{"pdp"}, Usage: "provide this flag if you want to append registry name to duplicate profiles"},
&cli.BoolFlag{Name: "write-on-sync-failure", Aliases: []string{"wosf"}, Usage: "always overwrite AWS config, even if sync fails"},
&cli.StringSliceFlag{Name: "required-key", Aliases: []string{"r", "requiredKey"}, Usage: "used to bypass the prompt or override user specific values"}},
ArgsUsage: "--name <registry_name> --url <repository_url>",
Action: func(c *cli.Context) error {
Expand All @@ -44,6 +45,7 @@ var AddCommand = cli.Command{
ref := c.String("ref")
prefixAllProfiles := c.Bool("prefix-all-profiles")
prefixDuplicateProfiles := c.Bool("prefix-duplicate-profiles")
writeOnSyncFailure := c.Bool("write-on-sync-failure")
requiredKey := c.StringSlice("required-key")
priority := c.Int("priority")

Expand All @@ -64,6 +66,7 @@ var AddCommand = cli.Command{
priority: priority,
prefixAllProfiles: prefixAllProfiles,
prefixDuplicateProfiles: prefixDuplicateProfiles,
writeOnSyncFailure: writeOnSyncFailure,
})

repoDirPath, err := getRegistryLocation(registry.Config)
Expand Down
12 changes: 10 additions & 2 deletions pkg/granted/registry/ini.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,24 @@ func loadAWSConfigFile() (*ini.File, string, error) {
return nil, "", err
}

awsConfig, err := loadAWSConfigFileFromPath(filepath)
if err != nil {
return nil, "", err
}
return awsConfig, filepath, nil
}

func loadAWSConfigFileFromPath(filepath string) (*ini.File, error) {
awsConfig, err := ini.LoadSources(ini.LoadOptions{
SkipUnrecognizableLines: true,
AllowNonUniqueSections: true,
AllowNestedValues: true,
}, filepath)
if err != nil {
return nil, "", err
return nil, err
}

return awsConfig, filepath, nil
return awsConfig, nil
}

// load all cloned configs of a single repo into one ini object.
Expand Down
2 changes: 2 additions & 0 deletions pkg/granted/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type registryOptions struct {
priority int
prefixAllProfiles bool
prefixDuplicateProfiles bool
writeOnSyncFailure bool
}

func NewProfileRegistry(rOpts registryOptions) Registry {
Expand All @@ -79,6 +80,7 @@ func NewProfileRegistry(rOpts registryOptions) Registry {
URL: rOpts.url,
PrefixAllProfiles: rOpts.prefixAllProfiles,
PrefixDuplicateProfiles: rOpts.prefixDuplicateProfiles,
WriteOnSyncFailure: rOpts.writeOnSyncFailure,
},
}

Expand Down
62 changes: 55 additions & 7 deletions pkg/granted/registry/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@ package registry

import (
"fmt"
"io"
"os"
"path"

"github.com/common-fate/clio"
grantedConfig "github.com/common-fate/granted/pkg/config"
"github.com/urfave/cli/v2"
"gopkg.in/ini.v1"
)

const (
SyncTempDirPrefix = "granted-registry-sync"
)

var SyncCommand = cli.Command{
Name: "sync",
Usage: "Pull the latest change from remote origin and sync aws profiles in aws config files",
Expand Down Expand Up @@ -43,13 +49,32 @@ func SyncProfileRegistries(shouldSilentLog bool, promptUserIfProfileDuplication
clio.Warn("granted registry not configured. Try adding a git repository with 'granted registry add <https://github.com/your-org/your-registry.git>'")
}

configFile, awsConfigPath, err := loadAWSConfigFile()
awsConfigPath, err := getDefaultAWSConfigLocation()
if err != nil {
return err
}

tmpDir, err := os.MkdirTemp("", SyncTempDirPrefix)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
if err := os.Chmod(tmpDir, 0755); err != nil {
return err
}

tmpConfigPath := path.Join(tmpDir, "aws-config")
if err := copyFile(awsConfigPath, tmpConfigPath); err != nil {
return fmt.Errorf("failed to copy aws config to tempfile for update")
}

configFile, err := loadAWSConfigFileFromPath(tmpConfigPath)
if err != nil {
return err
}

// if the config file contains granted generated content then remove it
if err := removeAutogeneratedProfiles(configFile, awsConfigPath); err != nil {
if err := removeAutogeneratedProfiles(configFile, tmpConfigPath); err != nil {
return err
}

Expand All @@ -59,7 +84,7 @@ func SyncProfileRegistries(shouldSilentLog bool, promptUserIfProfileDuplication
isFirstSection = true
}

err = runSync(&r, configFile, awsConfigPath, syncOpts{
err = runSync(&r, configFile, tmpConfigPath, syncOpts{
isFirstSection: isFirstSection,
shouldSilentLog: shouldSilentLog,
promptUserIfProfileDuplication: promptUserIfProfileDuplication,
Expand All @@ -69,16 +94,23 @@ func SyncProfileRegistries(shouldSilentLog bool, promptUserIfProfileDuplication
if err != nil {
se, ok := err.(*SyncError)
if ok {
clio.Warnf("Sync failed for registry %s", r.Config.Name)
clio.Debug(se.Error())
clio.Errorf("Sync failed for registry %s: %s", r.Config.Name, se.Error())

// skip syncing for this registry but continue syncing for other registries.
continue
if r.Config.WriteOnSyncFailure {
clio.Warnf("%s is configured to write on sync failure; continuing.", r.Config.Name)
continue
}
}
return err
}
}

// Run only if all syncs have succeeded
clio.Debugf("sync successful; moving %s to %s", tmpConfigPath, awsConfigPath)
if err := os.Rename(tmpConfigPath, awsConfigPath); err != nil {
return err
}

return nil
}

Expand Down Expand Up @@ -175,3 +207,19 @@ type SyncError struct {
func (m *SyncError) Error() string {
return fmt.Sprintf("Failed to sync for registry %s with error: %s", m.RegistryName, m.Err.Error())
}

func copyFile(from, to string) error {
copyFrom, err := os.Open(from)
if err != nil {
return err
}
defer copyFrom.Close()
copyTo, err := os.Create(to)
if err != nil {
return err
}
defer copyTo.Close()

_, err = io.Copy(copyFrom, copyTo)
return err
}

0 comments on commit dfa6ad4

Please sign in to comment.