<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/UKHomeOffice/aws_usersync/sync_iam"
	"github.com/UKHomeOffice/aws_usersync/sync_users"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/iam"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

const (
	version = "0.0.1"
)

// custom type for maps to userData
type userMap map[string]*userData

// structure to hold the user data for users
type userData struct {
	group string
	keys  []string
}

// Define variables flag and standard
var (
	keyEncoding = flag.String("e", "SSH", "SSH Key encoding type ssh-rsa or pem, defaults to SSH")
	sudoGroup   = flag.String("S", "sudo", "Group for the users to be part of for sudo, defaults to sudo group")
	groups      = flag.String("g", "", "Comma separated list of Group names in AWS")
	versionShow = flag.Bool("v", false, "Display the version")
	interval    = flag.Int("i", 30, "The frequency to poll in Minutes, for updates from the cloud provider")
	ignoreusers = flag.String("I", "root,coreos", "Specify comma separated list of users to ignore on the system so they wont be attempted to be removed")
	onetime     = flag.Bool("o", true, "One time run as oppose polling and daemonizing")
	region      = flag.String("r", "eu-west-1", "AWS Region, defaults to eu-west-1")
	binName     = "coreos_awsusermgt"
	grpList     []string
)

// wrapper function for stderr
func stderr(f string, a ...interface{}) {
	out := fmt.Sprintf(f, a...)
	fmt.Fprintln(os.Stderr, strings.TrimSuffix(out, "\n"))
}

// wrapper function for stdout
func stdout(f string, a ...interface{}) {
	out := fmt.Sprintf(f, a...)
	fmt.Fprintln(os.Stdout, strings.TrimSuffix(out, "\n"))
}

// wrapper function for panic
func panicf(f string, a ...interface{}) {
	panic(fmt.Sprintf(f, a...))
}

// Split the group list into an array
func splitString(g string) []string {
	glist := strings.Split(strings.Replace(g, " ", "", -1), ",")
	return glist
}

// Set the key in the structure for the user fetched from iam or delete user from
// structure if the user hasn't set a key
func (u userMap) setKey(svc *iam.IAM) error {
	for user, struc := range u {
		keys, err := sync_iam.GetKeys(user, svc)
		if err != nil {
			stderr("Error occurred getting keys: %v", err)
			return err
		}
		if len(keys) == 0 {
			stdout("No active keys for \"%v\". Not adding user (get them to add their key)\n", user)
			delete(u, user)
		} else {
			struc.keys = keys
		}
	}
	return nil
}

// Set the IAM users
func (u userMap) setIamUsers(svc *iam.IAM, g []string) error {
	for _, grp := range g {
		resp, err := svc.GetGroup(&iam.GetGroupInput{GroupName: aws.String(grp)})
		if err != nil {
			stderr("Error getting Group: %v, %v", grp, err)
			return err
		}
		for _, user := range sync_iam.GetIamUsers(resp) {
			u[user] = &userData{group: grp}
		}
	}
	return nil
}

func (u userMap) printMap() {
	for user, struc := range u {
		fmt.Printf("\nUser: %v, Data: %+v\n", user, struc)
	}
}

// Return the difference between iam users and local users as array
func (u userMap) diffUsers() []string {
	var iamusers []string
	localusers, err := sync_users.GetAllUsers()
	stdout("Localusers: %v", localusers)
	if err != nil {
		stderr("An error occured grabbing users from system: %v", err)
	}
	for user, _ := range u {
		iamusers = append(iamusers, user)
	}
	diffusers := sync_users.GetArrayDiff(iamusers, localusers)
	return diffusers
}

// Take in the channels and loop continuously through until we need to break
// syncing uses with whatever the time interval supplied is
func (u userMap) process(grp []string, doneChan chan bool, stopChan chan bool, interval int) {
	defer close(doneChan)
	for {
		u.userSync(grp)
		select {
		case <-stopChan:
			break
		case <-time.After(time.Duration(interval) * time.Minute):
			continue
		}
	}
}

// Loop through all the users and add user locally to main which will call sync
// we need to call dokeys on if the user exists or not so need to check the error message
// for whether the user exists or not and run it anyway unless some other error
func (u userMap) userSync(grp []string) error {
	// set region
	cfg := &aws.Config{Region: aws.String(*region)}

	// set Iam service
	iamsvc := sync_iam.GetIamClient(cfg)

	// Fetch all iam users from group and assign to userMap type
	if err := u.setIamUsers(iamsvc, grp); err != nil {
		return err
	}

	// Set all the keys for users
	if err := u.setKey(iamsvc); err != nil {
		return err
	}
  var IamUsers []string
	for userStr, data := range u {
		IamUsers = append(IamUsers, userStr)
		luser := sync_users.New(userStr, data.group, *sudoGroup, data.keys)
		out, err := luser.Sync()
		if err != nil {
			stderr("Error syncing users: %v", err)
			return err
		}
		if len(out) >= 1 {
			stdout("User Info ..... :: %v", out)
		}
	}
	ignored := splitString(*ignoreusers)
	userCmp, err := sync_users.CmpNew(IamUsers, ignored)<commit_msg>adding in changes for interval and merge<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/UKHomeOffice/aws_usersync/sync_iam"
	"github.com/UKHomeOffice/aws_usersync/sync_users"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/iam"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

const (
	version = "0.0.1"
)

// custom type for maps to userData
type userMap map[string]*userData

// structure to hold the user data for users
type userData struct {
	group string
	keys  []string
}

// Define variables flag and standard
var (
	keyEncoding = flag.String("e", "SSH", "SSH Key encoding type ssh-rsa or pem, defaults to SSH")
	sudoGroup   = flag.String("S", "sudo", "Group for the users to be part of for sudo, defaults to sudo group")
	groups      = flag.String("g", "", "Comma separated list of Group names in AWS")
	versionShow = flag.Bool("v", false, "Display the version")
	interval    = flag.Int("i", 30, "The frequency to poll in Minutes, for updates from the cloud provider")
	ignoreusers = flag.String("I", "root,coreos", "Specify comma separated list of users to ignore on the system so they wont be attempted to be removed")
	onetime     = flag.Bool("o", true, "One time run as oppose polling and daemonizing")
	region      = flag.String("r", "eu-west-1", "AWS Region, defaults to eu-west-1")
	binName     = "coreos_awsusermgt"
	grpList     []string
)

// wrapper function for stderr
func stderr(f string, a ...interface{}) {
	out := fmt.Sprintf(f, a...)
	fmt.Fprintln(os.Stderr, strings.TrimSuffix(out, "\n"))
}

// wrapper function for stdout
func stdout(f string, a ...interface{}) {
	out := fmt.Sprintf(f, a...)
	fmt.Fprintln(os.Stdout, strings.TrimSuffix(out, "\n"))
}

// wrapper function for panic
func panicf(f string, a ...interface{}) {
	panic(fmt.Sprintf(f, a...))
}

// Split the group list into an array
func splitString(g string) []string {
	glist := strings.Split(strings.Replace(g, " ", "", -1), ",")
	return glist
}

// Set the key in the structure for the user fetched from iam or delete user from
// structure if the user hasn't set a key
func (u userMap) setKey(svc *iam.IAM) error {
	for user, struc := range u {
		keys, err := sync_iam.GetKeys(user, svc)
		if err != nil {
			stderr("Error occurred getting keys: %v", err)
			return err
		}
		if len(keys) == 0 {
			stdout("No active keys for \"%v\". Not adding user (get them to add their key)\n", user)
			delete(u, user)
		} else {
			struc.keys = keys
		}
	}
	return nil
}

// Set the IAM users
func (u userMap) setIamUsers(svc *iam.IAM, g []string) error {
	for _, grp := range g {
		resp, err := svc.GetGroup(&iam.GetGroupInput{GroupName: aws.String(grp)})
		if err != nil {
			stderr("Error getting Group: %v, %v", grp, err)
			return err
		}
		for _, user := range sync_iam.GetIamUsers(resp) {
			u[user] = &userData{group: grp}
		}
	}
	return nil
}

func (u userMap) printMap() {
	for user, struc := range u {
		fmt.Printf("\nUser: %v, Data: %+v\n", user, struc)
	}
}

// Return the difference between iam users and local users as array
func (u userMap) diffUsers() []string {
	var iamusers []string
	localusers, err := sync_users.GetAllUsers()
	stdout("Localusers: %v", localusers)
	if err != nil {
		stderr("An error occured grabbing users from system: %v", err)
	}
	for user, _ := range u {
		iamusers = append(iamusers, user)
	}
	diffusers := sync_users.GetArrayDiff(iamusers, localusers)
	return diffusers
}

// Take in the channels and loop continuously through until we need to break
// syncing uses with whatever the time interval supplied is
func (u userMap) process(grp []string, doneChan chan bool, stopChan chan bool, interval int) {
	defer close(doneChan)
	for {
		u.userSync(grp)
		select {
		case <-stopChan:
			break
		case <-time.After(time.Duration(interval) * time.Minute):
			continue
		}
	}
}

// Loop through all the users and add user locally to main which will call sync
// we need to call dokeys on if the user exists or not so need to check the error message
// for whether the user exists or not and run it anyway unless some other error
func (u userMap) userSync(grp []string) error {
	// set region
	cfg := &aws.Config{Region: aws.String(*region)}

	// set Iam service
	iamsvc := sync_iam.GetIamClient(cfg)

	// Fetch all iam users from group and assign to userMap type
	if err := u.setIamUsers(iamsvc, grp); err != nil {
		return err
	}

	// Set all the keys for users
	if err := u.setKey(iamsvc); err != nil {
		return err
	}
	var IamUsers []string
	for userStr, data := range u {
		IamUsers = append(IamUsers, userStr)
		luser := sync_users.New(userStr, data.group, *sudoGroup, data.keys)
		out, err := luser.Sync()
		if err != nil {
			stderr("Error syncing users: %v", err)
			return err
		}
		if len(out) >= 1 {
			stdout("User Info ..... :: %v", out)
		}
	}
	ignored := splitString(*ignoreusers)
	userCmp, err := sync_users.CmpNew(IamUsers, ignored)
{'fraction_non_alphanumeric': 0.13434054716210697, 'fraction_numerical': 0.002041649652919559, 'mean_word_length': 3.5866104868913857, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3863848', 'n_tokens_mistral': 3533, 'n_tokens_neox': 3363, 'n_words': 1157}