github.com/Cloud-Foundations/Dominator@v0.3.4/cmd/ami-publisher/unusedImages.go (about) 1 package main 2 3 import ( 4 "encoding/csv" 5 "fmt" 6 "os" 7 "strconv" 8 "syscall" 9 10 "github.com/Cloud-Foundations/Dominator/imagepublishers/amipublisher" 11 "github.com/Cloud-Foundations/Dominator/lib/fsutil" 12 libjson "github.com/Cloud-Foundations/Dominator/lib/json" 13 "github.com/Cloud-Foundations/Dominator/lib/log" 14 "github.com/Cloud-Foundations/Dominator/lib/stringutil" 15 libtags "github.com/Cloud-Foundations/Dominator/lib/tags" 16 ) 17 18 const ( 19 filePerms = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IRGRP | 20 syscall.S_IROTH 21 ) 22 23 func listUnusedImagesSubcommand(args []string, logger log.DebugLogger) error { 24 if err := listUnusedImages(logger); err != nil { 25 return fmt.Errorf("error listing unused images: %s", err) 26 } 27 logMemoryUsage(logger) 28 return nil 29 } 30 31 func listUnusedImages(logger log.DebugLogger) error { 32 results, err := amipublisher.ListUnusedImages(targets, skipTargets, 33 searchTags, excludeSearchTags, *minImageAge, logger) 34 if err != nil { 35 return err 36 } 37 if err := libjson.WriteWithIndent(os.Stdout, " ", results); err != nil { 38 return err 39 } 40 if *oldImageInstancesCsvFile != "" { 41 err := writeInstancesCsv(*oldImageInstancesCsvFile, 42 results.OldInstances) 43 if err != nil { 44 return err 45 } 46 } 47 if *unusedImagesCsvFile != "" { 48 err := writeUnusedImagesCsv(*unusedImagesCsvFile, 49 results.UnusedImages) 50 if err != nil { 51 return err 52 } 53 } 54 return nil 55 } 56 57 func writeInstancesCsv(filename string, 58 instances []amipublisher.Instance) error { 59 file, err := fsutil.CreateRenamingWriter(filename, filePerms) 60 if err != nil { 61 return err 62 } 63 defer file.Close() 64 writer := csv.NewWriter(file) 65 defer writer.Flush() 66 // First find all the tag keys. 67 tagKeysSet := make(map[string]struct{}) 68 for _, instance := range instances { 69 for key := range instance.Tags { 70 tagKeysSet[key] = struct{}{} 71 } 72 } 73 tagKeysList := stringutil.ConvertMapKeysToList(tagKeysSet, true) 74 header := []string{"Account", "Region", "AmiId", "InstanceId", "LaunchTime"} 75 header = append(header, tagKeysList...) 76 if err := writer.Write(header); err != nil { 77 return err 78 } 79 for _, instance := range instances { 80 record := []string{ 81 instance.AccountName, 82 instance.Region, 83 instance.AmiId, 84 instance.InstanceId, 85 instance.LaunchTime, 86 } 87 err := appendRecordAndWrite(writer, record, tagKeysList, instance.Tags) 88 if err != nil { 89 return err 90 } 91 } 92 return nil 93 } 94 95 func writeUnusedImagesCsv(filename string, 96 images []amipublisher.Image) error { 97 file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, filePerms) 98 if err != nil { 99 return err 100 } 101 defer file.Close() 102 writer := csv.NewWriter(file) 103 defer writer.Flush() 104 // First find all the tag keys. 105 tagKeysSet := make(map[string]struct{}) 106 for _, image := range images { 107 for key := range image.Tags { 108 tagKeysSet[key] = struct{}{} 109 } 110 } 111 tagKeysList := stringutil.ConvertMapKeysToList(tagKeysSet, true) 112 header := []string{ 113 "Account", 114 "Region", 115 "AmiId", 116 "AmiName", 117 "CreationDate", 118 "Description", 119 "Size", 120 } 121 header = append(header, tagKeysList...) 122 if err := writer.Write(header); err != nil { 123 return err 124 } 125 for _, image := range images { 126 record := []string{ 127 image.AccountName, 128 image.Region, 129 image.AmiId, 130 image.AmiName, 131 image.CreationDate, 132 image.Description, 133 strconv.Itoa(int(image.Size)), 134 } 135 err := appendRecordAndWrite(writer, record, tagKeysList, image.Tags) 136 if err != nil { 137 return err 138 } 139 } 140 return nil 141 } 142 143 func appendRecordAndWrite(writer *csv.Writer, record []string, 144 tagKeysList []string, tags libtags.Tags) error { 145 for _, key := range tagKeysList { 146 value := tags[key] 147 record = append(record, value) 148 } 149 return writer.Write(record) 150 } 151 152 func deleteUnusedImagesSubcommand(args []string, logger log.DebugLogger) error { 153 if err := deleteUnusedImages(logger); err != nil { 154 return fmt.Errorf("error deleting unused images: %s", err) 155 } 156 logMemoryUsage(logger) 157 return nil 158 } 159 160 func deleteUnusedImages(logger log.DebugLogger) error { 161 results, err := amipublisher.DeleteUnusedImages(targets, skipTargets, 162 searchTags, excludeSearchTags, *minImageAge, logger) 163 if err != nil { 164 return err 165 } 166 return libjson.WriteWithIndent(os.Stdout, " ", results) 167 }