diff --git a/.github/workflows/audit.yaml b/.github/workflows/audit.yaml index 5e37a2a..3664702 100644 --- a/.github/workflows/audit.yaml +++ b/.github/workflows/audit.yaml @@ -32,6 +32,8 @@ jobs: CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -v -o build/today ./cmd/today CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -v -o build/mdtoc ./cmd/mdtoc CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -v -o build/achelper ./cmd/achelper + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -v -o build/namegen ./cmd/namegen + CGO_ENABLED=0 GOOS="linux" GOARCH="amd64" go build -v -o build/invgen ./cmd/invgen - name: Run go vet run: go vet ./... diff --git a/cmd/invgen/main.go b/cmd/invgen/main.go new file mode 100644 index 0000000..b5844ab --- /dev/null +++ b/cmd/invgen/main.go @@ -0,0 +1,310 @@ +package main + +import ( + "fmt" + "math/rand" + "os" + "runtime" + "strconv" + "strings" + "time" + + "github.com/goombaio/namegenerator" + log "github.com/sirupsen/logrus" +) + +type Host struct { + Name string + Continent string + Region string + City string + Team string + Purpose string +} + +// Geographic hierarchy +var locations = map[string][][]string{ + "US": { + {"US", "NY", "NewYork"}, + // {"US", "CA", "sanfransisco"}, + {"US", "TX", "austen"}, + }, + "EU": { + {"EU", "NL", "AMSterdam"}, + {"EU", "NL", "Eindhoven"}, + // {"EU", "DE", "BERlin"}, + {"EU", "FR", "PARis"}, + }, + /* + "ASIA": { + {"ASIA", "JP", "TOKio"}, + {"ASIA", "IN", "DELi"}, + {"ASIA", "CN", "bejing"}, + }, + */ +} + +var Teams = []string{ + "team1", + "team2", + "team3", + "team4", + "team5", +} +var Purpose = []string{ + "prod", + "dev", + "qa", + "test", +} + +func init() { + log.SetFormatter(&log.TextFormatter{ + FullTimestamp: true, + DisableLevelTruncation: true, + TimestampFormat: "2006-01-02 15:04:05", + }) + + // Output to stdout instead of the default stderr + // Can be any io.Writer, see below for File example + log.SetOutput(os.Stdout) + + // Only log the warning severity or above. + log.SetLevel(log.InfoLevel) + +} + +func LogIfError(msg interface{}) { + if msg == nil { + return + } + pc, _, _, _ := runtime.Caller(1) + elements := strings.Split(runtime.FuncForPC(pc).Name(), ".") + log.Errorf("%s: return not nil: %s", elements[len(elements)-1], msg) +} +func LogIfWriteError(n int, err error) { + if err == nil { + return + } + pc, _, _, _ := runtime.Caller(1) + elements := strings.Split(runtime.FuncForPC(pc).Name(), ".") + log.Errorf("%s: return not nil: %s", elements[len(elements)-1], err) +} + +func mkdirRecursive(directory string) { + _, err := os.Stat(directory) + if os.IsNotExist(err) { + LogIfError(os.MkdirAll(directory, 0755)) + } +} + +func printMkDirPerListItem(prefix string, fields []string) { + directories := []string{} + for _, field := range fields { + directories = append(directories, fmt.Sprintf("%s_%s", prefix, field)) + } + + for _, field := range directories { + mkdirRecursive(fmt.Sprintf("group_vars/%s", field)) + + // write a file in the directory + w, err := os.Create(fmt.Sprintf("group_vars/%s/vars.yml", field)) + if err != nil { + fmt.Println("Error: Cannot create file") + return + } + defer w.Close() + LogIfWriteError(w.WriteString("---\n")) + LogIfWriteError(w.WriteString(fmt.Sprintf("%s_token: %s\n", prefix, field))) + LogIfWriteError(w.WriteString("...\n")) + + } +} + +func printMkDirPerLocation() { + prefix := "l" + directories := []string{} + for continent, regions := range locations { + for _, region := range regions { + col1 := strings.ToLower(continent) + col2 := strings.ToLower(region[1]) + col3 := strings.ToLower(region[2]) + + directories = append(directories, fmt.Sprintf("%s_%s_%s_%s", prefix, col1, col2, col3)) + directories = append(directories, fmt.Sprintf("%s_%s_%s", prefix, col1, col2)) + directories = append(directories, fmt.Sprintf("%s_%s", prefix, col1)) + + } + } + for _, field := range directories { + mkdirRecursive(fmt.Sprintf("group_vars/%s", field)) + + // write a file in the directory + w, err := os.Create(fmt.Sprintf("group_vars/%s/vars.yml", field)) + if err != nil { + fmt.Println("Error: Cannot create file") + return + } + defer w.Close() + LogIfWriteError(w.WriteString("---\n")) + LogIfWriteError(w.WriteString(fmt.Sprintf("%s_token: %s\n", prefix, field))) + LogIfWriteError(w.WriteString("...\n")) + + } +} + +func groupHostsByFields(hosts []Host, prefix string, fields []string) map[string][]string { + retv := make(map[string][]string) + + for _, host := range hosts { + index := "" + for _, field := range fields { + switch field { + case "Continent": + index = host.Continent + case "Region": + index = fmt.Sprintf("%s_%s", host.Continent, host.Region) + case "City": + index = fmt.Sprintf("%s_%s_%s", host.Continent, host.Region, host.City) + case "Team": + index = host.Team + case "Purpose": + index = host.Purpose + } + } + index = fmt.Sprintf("%s_%s", prefix, index) + retv[index] = append(retv[index], host.Name) + } + return retv +} + +func groupHostsByContinent(hosts []Host) map[string][]string { + return groupHostsByFields(hosts, "l", []string{"Continent"}) +} + +func groupHostsByRegion(hosts []Host) map[string][]string { + return groupHostsByFields(hosts, "l", []string{"Continent", "Region"}) +} + +func groupHostsByCity(hosts []Host) map[string][]string { + return groupHostsByFields(hosts, "l", []string{"Continent", "Region", "City"}) +} + +func groupHostsByTeam(hosts []Host) map[string][]string { + return groupHostsByFields(hosts, "t", []string{"Team"}) +} + +func groupHostsByPurpose(hosts []Host) map[string][]string { + return groupHostsByFields(hosts, "p", []string{"Purpose"}) +} + +func writeGroup(w *os.File, group map[string][]string, priority int) { + for continent, names := range group { + fmt.Fprintf(w, "%s:\n", continent) + fmt.Fprintf(w, " vars:\n") + fmt.Fprintf(w, " ansible_group_priority: %d\n", priority) + fmt.Fprintf(w, " hosts:\n") + for _, hn := range names { + fmt.Fprintf(w, " %s:\n", hn) + } + } +} + +func RandomFromList(inlist []string) string { + // rand.Seed(time.Now().UnixNano()) + return inlist[rand.Intn(len(inlist))] +} + +// Generate a random location slice +func randomLocation() []string { + // rand.Seed(time.Now().UnixNano()) + + // Get random continent key + keys := make([]string, 0, len(locations)) + for k := range locations { + keys = append(keys, k) + } + randomKey := keys[rand.Intn(len(keys))] + + // Get random location slice from that key + place := locations[randomKey] + return place[rand.Intn(len(place))] +} + +func generateHost() *Host { + seed := time.Now().UTC().UnixNano() + nameGenerator := namegenerator.NewNameGenerator(seed) + items := randomLocation() + + retv := &Host{} + retv.Name = nameGenerator.Generate() + retv.Continent = strings.ToLower(items[0]) + retv.Region = strings.ToLower(items[1]) + retv.City = strings.ToLower(items[2]) + retv.Team = RandomFromList(Teams) + retv.Purpose = RandomFromList(Purpose) + + return retv +} + +func writeHost(w *os.File, host *Host) { + fmt.Fprintf(w, " %s:\n", host.Name) + fmt.Fprintf(w, " continent: %s\n", host.Continent) + fmt.Fprintf(w, " region: %s\n", host.Region) + fmt.Fprintf(w, " city: %s\n", host.City) + fmt.Fprintf(w, " team: %s\n", host.Team) + fmt.Fprintf(w, " purpose: %s\n", host.Purpose) +} + +func writeHostsFile(outputfile string, hosts []Host) { + w, err := os.Create(outputfile) + if err != nil { + fmt.Println("Error: Cannot create file") + return + } + defer w.Close() + + LogIfWriteError(w.WriteString("---\n")) + LogIfWriteError(w.WriteString("all:\n")) + LogIfWriteError(w.WriteString(" hosts:\n")) + for _, host := range hosts { + writeHost(w, &host) + } + continentList := groupHostsByContinent(hosts) + regionList := groupHostsByRegion(hosts) + cityList := groupHostsByCity(hosts) + teamList := groupHostsByTeam(hosts) + purposeList := groupHostsByPurpose(hosts) + + writeGroup(w, continentList, 10) + writeGroup(w, regionList, 20) + writeGroup(w, cityList, 30) + writeGroup(w, teamList, 100) + writeGroup(w, purposeList, 110) + +} + +func main() { + hosts := []Host{} + NumberOfHosts := 5 + var err error + + if len(os.Args) > 1 { + firstArg := os.Args[1] + NumberOfHosts, err = strconv.Atoi(firstArg) + if err != nil { + fmt.Println("Error: Argument is not a valid integer") + return + } + } + + for i := 1; i < NumberOfHosts; i++ { + r := generateHost() + hosts = append(hosts, *r) + } + writeHostsFile("hosts.yml", hosts) + + printMkDirPerListItem("t", Teams) + printMkDirPerListItem("p", Purpose) + printMkDirPerLocation() +} diff --git a/cmd/logging/common.go b/cmd/logging/common.go index 725fd72..00cf008 100644 --- a/cmd/logging/common.go +++ b/cmd/logging/common.go @@ -25,7 +25,9 @@ func handleLogCmd(cmd *cobra.Command, args []string) { if len(args) == 0 { log.Error("No message provided") - cmd.Help() + if err := cmd.Help(); err != nil { + log.Error(err) + } os.Exit(1) } logmsg := logging.NewLogMessage(cmd.Use) diff --git a/cmd/namegen/main.go b/cmd/namegen/main.go new file mode 100644 index 0000000..fd6de2e --- /dev/null +++ b/cmd/namegen/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + "time" + + "github.com/goombaio/namegenerator" +) + +func main() { + seed := time.Now().UTC().UnixNano() + nameGenerator := namegenerator.NewNameGenerator(seed) + + name := nameGenerator.Generate() + + fmt.Println(name) +} diff --git a/go.mod b/go.mod index e711be8..083e440 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.21 require ( github.com/fatih/color v1.17.0 + github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e github.com/mitchellh/go-wordwrap v1.0.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.1 diff --git a/go.sum b/go.sum index 54e6d02..e51919f 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e h1:XmA6L9IPRdUr28a+SK/oMchGgQy159wvzXA5tJ7l+40= +github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e/go.mod h1:AFIo+02s+12CEg8Gzz9kzhCbmbq6JcKNrhHffCGA9z4= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=