registry

package
v0.13.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 31, 2023 License: MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
const AUTO_GENERATED_MSG string = `` /* 414-byte string literal not displayed */
View Source
const (
	// permission for user to read/write/execute.
	USER_READ_WRITE_PERM = 0700
)

Variables

View Source
var AddCommand = cli.Command{
	Name:        "add",
	Description: "Add a Profile Registry that you want to sync with aws config file",
	Usage:       "Provide git repository you want to sync with aws config file",
	Flags: []cli.Flag{
		&cli.StringFlag{Name: "name", Required: true, Usage: "name is used to uniquely identify profile registries", Aliases: []string{"n"}},
		&cli.StringFlag{Name: "url", Required: true, Usage: "git url for the remote repository", Aliases: []string{"u"}},
		&cli.StringFlag{Name: "path", Usage: "provide path if only the subfolder needs to be synced", Aliases: []string{"p"}},
		&cli.StringFlag{Name: "filename", Aliases: []string{"f"}, Usage: "provide filename if yml file is not granted.yml", DefaultText: "granted.yml"},
		&cli.IntFlag{Name: "priority", Usage: "profile registry will be sorted by priority descending", Value: 0},
		&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.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 {
		gConf, err := grantedConfig.Load()
		if err != nil {
			return err
		}

		name := c.String("name")
		gitURL := c.String("url")
		pathFlag := c.String("path")
		configFileName := c.String("filename")
		ref := c.String("ref")
		prefixAllProfiles := c.Bool("prefix-all-profiles")
		prefixDuplicateProfiles := c.Bool("prefix-duplicate-profiles")
		requiredKey := c.StringSlice("required-key")
		priority := c.Int("priority")

		for _, r := range gConf.ProfileRegistry.Registries {
			if r.Name == name {
				clio.Errorf("profile registry with name '%s' already exists. Name is required to be unique. Try adding with different name.\n", name)

				return nil
			}
		}

		registry := NewProfileRegistry(registryOptions{
			name:                    name,
			path:                    pathFlag,
			configFileName:          configFileName,
			url:                     gitURL,
			ref:                     ref,
			priority:                priority,
			prefixAllProfiles:       prefixAllProfiles,
			prefixDuplicateProfiles: prefixDuplicateProfiles,
		})

		repoDirPath, err := getRegistryLocation(registry.Config)
		if err != nil {
			return err
		}

		if _, err = os.Stat(repoDirPath); err != nil {
			err = gitClone(gitURL, repoDirPath)
			if err != nil {
				return err
			}

		} else {
			err = gitPull(repoDirPath, false)
			if err != nil {
				return err
			}
		}

		err = registry.Parse()
		if err != nil {
			return err
		}

		err = registry.PromptRequiredKeys(requiredKey, false)
		if err != nil {
			return err
		}

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

		if _, err := os.Stat(awsConfigPath); os.IsNotExist(err) {
			clio.Debugf("%s file does not exist. Creating an empty file\n", awsConfigPath)

			err := os.MkdirAll(path.Dir(awsConfigPath), USER_READ_WRITE_PERM)
			if err != nil {
				return err
			}

			_, err = os.Create(awsConfigPath)
			if err != nil {
				return fmt.Errorf("unable to create : %s", err)
			}
		}

		isFirstSection := false
		allRegistries, err := GetProfileRegistries()
		if err != nil {
			return err
		}

		if len(allRegistries) == 0 {
			isFirstSection = true
		}

		awsConfigFile, filepath, err := loadAWSConfigFile()
		if err != nil {
			return err
		}

		if err := Sync(&registry, awsConfigFile, syncOpts{
			isFirstSection:                 isFirstSection,
			promptUserIfProfileDuplication: true,
			shouldSilentLog:                false,
			shouldFailForRequiredKeys:      false,
		}); err != nil {
			return err
		}

		gConf, err = grantedConfig.Load()
		if err != nil {
			return err
		}

		gConf.ProfileRegistry.Registries = append(gConf.ProfileRegistry.Registries, registry.Config)
		err = gConf.Save()
		if err != nil {
			return err
		}

		if priority > 0 {
			allRegistries, err = GetProfileRegistries()
			if err != nil {
				return err
			}

			if len(allRegistries) > 1 {
				var currentHighest int = 0
				if allRegistries[1].Config.Priority != nil {
					currentHighest = *allRegistries[1].Config.Priority
				}

				if currentHighest < priority {
					err = removeAutogeneratedProfiles(awsConfigFile, filepath)
					if err != nil {
						return err
					}

					clio.Debugf("New Registry has higher priority, resyncing all registries in new order...")
					err = SyncProfileRegistries(false, false, false)
					if err != nil {
						return err
					}

					return nil
				}
			}
		}

		err = awsConfigFile.SaveTo(filepath)
		if err != nil {
			return err
		}

		return nil
	},
}
View Source
var MigrateCommand = cli.Command{
	Name:        "migrate",
	Description: "Migrate Profile Registry Configuration",
	Usage:       "Migrate Profile Registry Configuration",

	Action: func(c *cli.Context) error {
		gConf, err := grantedConfig.Load()
		if err != nil {
			clio.Debug(err.Error())
		}

		if len(gConf.ProfileRegistryURLS) > 0 {
			var registries []grantedConfig.Registry
			for i, u := range gConf.ProfileRegistryURLS {
				var msg survey.Input
				if i > 0 {
					msg = survey.Input{Message: fmt.Sprintf("Enter a registry name for %s", u), Default: fmt.Sprintf("granted-registry-%d", i)}
				} else {
					msg = survey.Input{Message: fmt.Sprintf("Enter a registry name for %s", u), Default: "granted-registry"}
				}

				var selected string
				err := testable.AskOne(&msg, &selected)
				if err != nil {
					return err
				}

				registries = append(registries, grantedConfig.Registry{
					Name: selected,
					URL:  u,
				})

			}

			gConf.ProfileRegistry.Registries = registries
			gConf.ProfileRegistryURLS = nil

			err = gConf.Save()
			if err != nil {
				clio.Debug(err.Error())
				return err
			}

			clio.Success("Successfully migrated your configuration.")

			return nil
		}

		clio.Infof("Your Profile Registry already has the latest configuration. No action required.")

		return nil
	},
}

Profile Registry data structure has been updated to accomodate different registry level options. If any user is using the previous configuration then prompt user to update the registry values.

View Source
var ProfileRegistryCommand = cli.Command{
	Name:        "registry",
	Usage:       "Manage Profile Registries",
	Description: "Profile Registries allow you to easily share AWS profile configuration in a team.",
	Subcommands: []*cli.Command{&AddCommand, &SyncCommand, &RemoveCommand, &MigrateCommand, &SetupCommand},
	Action: func(c *cli.Context) error {
		registries, err := GetProfileRegistries()
		if err != nil {
			return err
		}

		if len(registries) == 0 {
			clio.Warn("You haven't connected any Profile Registries yet.")
			clio.Info("Connect to a Profile Registry by running 'granted registry add -n <registry_name> -u <your_repo>'")
			return nil
		}

		clio.Info("Granted is currently synced with following registries:")
		for i, r := range registries {
			clio.Logf("\t %d: %s with name '%s'", (i + 1), r.Config.URL, r.Config.Name)
		}
		clio.NewLine()

		clio.Info("To add new registry use 'granted registry add <your_repo>'")
		clio.Info("To remove a registry use 'granted registry remove' and select from the options")
		clio.Info("To sync a registry use 'granted registry sync'")

		return nil
	},
}
View Source
var RemoveCommand = cli.Command{
	Name:        "remove",
	Description: "Unsubscribe from a Profile Registry",
	Usage:       "Unsubscribe from a Profile Registry",

	Action: func(c *cli.Context) error {
		gConf, err := grantedConfig.Load()
		if err != nil {
			return err
		}

		if len(gConf.ProfileRegistry.Registries) == 0 {
			clio.Error("There are no profile registries configured currently.\n Please use 'granted registry add <https://github.com/your-org/your-registry.git>' to add a new registry")
			return nil
		}

		registriesWithNames := []string{}

		for _, r := range gConf.ProfileRegistry.Registries {
			registriesWithNames = append(registriesWithNames, r.Name)
		}

		in := survey.Select{Message: "Please select the git repository you would like to unsubscribe:", Options: registriesWithNames}
		var out string
		err = testable.AskOne(&in, &out)
		if err != nil {
			return err
		}

		var selectedRegistry grantedConfig.Registry

		for _, r := range gConf.ProfileRegistry.Registries {
			if r.Name == out {
				selectedRegistry = r
			}
		}

		repoDir, err := getRegistryLocation(selectedRegistry)
		if err != nil {
			return err
		}

		err = removeAutogeneratedProfileByName(out)
		if err != nil {
			return err
		}

		err = os.RemoveAll(repoDir)
		if err != nil {
			return err
		}

		err = remove(gConf, out)
		if err != nil {
			return err
		}

		err = gConf.Save()
		if err != nil {
			return err
		}

		clio.Successf("Successfully unsubscribed from %s", out)

		return nil
	},
}
View Source
var SetupCommand = cli.Command{
	Name:        "setup",
	Usage:       "Setup a Profile Registry repository",
	Description: "Setup a granted registry repository",
	Subcommands: []*cli.Command{},
	Flags:       []cli.Flag{&cli.PathFlag{Name: "dir", Aliases: []string{"d"}, Usage: "Directory to setup the Profile Registry", Value: "granted-registry"}},
	Action: func(c *cli.Context) error {
		dir := c.Path("dir")

		err := ensureConfigDoesntExist(c, dir)
		if err != nil {
			return err
		}

		err = os.Mkdir(dir, 0755)
		if err != nil {
			return err
		}

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

		var confirm bool
		s := &survey.Confirm{
			Message: "Are you sure you want to copy all of the profiles from your AWS config file?",
			Default: true,
		}
		err = survey.AskOne(s, &confirm)
		if err != nil {
			return err
		}
		if !confirm {
			clio.Info("Cancelled registry setup")
			return nil
		}

		err = configFile.SaveTo(path.Join(dir, "config"))
		if err != nil {
			return err
		}

		f, err := os.Create(path.Join(dir, "granted.yml"))
		if err != nil {
			return err
		}
		defer f.Close()

		err = gitInit(dir)
		if err != nil {
			return err
		}

		_, err = f.WriteString(`awsConfig:
    - ./config`)
		if err != nil {
			return err
		}
		clio.Infof("Successfully created valid profile registry 'granted-registry' in %s.", dir)
		clio.Info("Now push this repository to remote origin so that your team-members can sync to it.")
		return nil
	},
}
View Source
var SyncCommand = cli.Command{
	Name:        "sync",
	Usage:       "Pull the latest change from remote origin and sync aws profiles in aws config files",
	Description: "Pull the latest change from remote origin and sync aws profiles in aws config files",
	Action: func(c *cli.Context) error {
		if err := SyncProfileRegistries(false, true, false); err != nil {
			return err
		}

		return nil
	},
}

Functions

func CheckoutRef

func CheckoutRef(ref string, repoDirPath string) error

set the path of the repo before checking out if a specific ref is passed we will checkout that ref can be a git hash, tag, or branch name. In that order

func Contains

func Contains(arr []string, s string) bool

func IsOutdatedConfig added in v0.6.0

func IsOutdatedConfig() bool

func SaveKey added in v0.6.0

func SaveKey(gConf *grantedConfig.Config, key string, value string) error

This is used when user passed the required value through flag.

func SaveKeys added in v0.6.0

func SaveKeys(gConf *grantedConfig.Config, ansmap map[string]interface{}) error

This is used when user enters the required key through cli prompts.

func Sync

func Sync(r *Registry, awsConfigFile *ini.File, opts syncOpts) error

Sync function will load all the configs provided in the clonedFile. and generate a new section in the ~/.aws/profile file.

func SyncProfileRegistries

func SyncProfileRegistries(shouldSilentLog bool, promptUserIfProfileDuplication bool, shouldFailForRequiredKeys bool) error

Wrapper around sync func. Check if profile registry is configured, pull the latest changes and call sync func. promptUserIfProfileDuplication if true will automatically prefix the duplicate profiles and won't prompt users this is useful when new registry with higher priority is added and there is duplication with lower priority registry.

Types

type ConfigTemplateVariables added in v0.6.0

type ConfigTemplateVariables struct {
	Required  map[string]string
	Variables map[string]string
	Profile   string
}

type Registry

type Registry struct {
	Config         grantedConfig.Registry
	AwsConfigPaths []string                         `yaml:"awsConfig"`
	TemplateValues []map[string][]map[string]string `yaml:"templateValues"`
}

func GetProfileRegistries added in v0.6.0

func GetProfileRegistries() ([]Registry, error)

func NewProfileRegistry added in v0.6.0

func NewProfileRegistry(rOpts registryOptions) Registry

func (*Registry) Parse

func (r *Registry) Parse() error

func (Registry) PromptRequiredKeys added in v0.6.0

func (r Registry) PromptRequiredKeys(passedKeys []string, shouldFailForRequiredKeys bool) error

granted.yml config might contain user specific variables in such case we would prompt users to add them before registry is added.

type SyncError added in v0.6.0

type SyncError struct {
	Err          error
	RegistryName string
}

func (*SyncError) Error added in v0.6.0

func (m *SyncError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL