func (c *Cache) MapImages() { // FIXME: add mutex if c.Manifest == nil || c.Api.Images == nil { return } c.Mapping.Images = make([]*ImageMapping, 0) logrus.Infof("Mapping images") for _, manifestImage := range c.Manifest.Images { imageMapping := ImageMapping{ ManifestName: manifestImage.FullName(), } imageMapping.Objects.Manifest = manifestImage imageMapping.Objects.GitHubRepo = c.GithubRepos[manifestImage.RepoPath()] imageMapping.Objects.GitHubLastRef = c.GithubLastRefs[manifestImage.RepoPath()] imageMapping.Objects.DockerHubTags = c.DockerHubTags[manifestImage.RepoPath()] manifestImageName := ImageCodeName(manifestImage.Name) apiImages := c.Api.Images for idx := range *apiImages { apiImage := (*apiImages)[idx] apiImageName := ImageCodeName(apiImage.Name) if rankMatch := fuzzy.RankMatch(manifestImageName, apiImageName); rankMatch > -1 { imageMapping.ApiUUID = apiImage.ID imageMapping.RankMatch = rankMatch imageMapping.Found++ imageMapping.Objects.Api = &apiImage } } c.Mapping.Images = append(c.Mapping.Images, &imageMapping) } logrus.Infof("Images mapped") }
func (c *Cache) MapImages() { // FIXME: add mutex if c.Manifest == nil || c.Api.Images == nil { return } c.Mapping.Images = make([]ImageMapping, 0) logrus.Infof("Mapping images") for _, manifestImage := range c.Manifest.Images { imageMapping := ImageMapping{ ManifestName: manifestImage.Name, } manifestImageName := ImageCodeName(manifestImage.Name) for _, apiImage := range *c.Api.Images { apiImageName := ImageCodeName(apiImage.Name) if rankMatch := fuzzy.RankMatch(manifestImageName, apiImageName); rankMatch > -1 { imageMapping.ApiUUID = apiImage.Identifier imageMapping.RankMatch = rankMatch imageMapping.Found++ } } c.Mapping.Images = append(c.Mapping.Images, imageMapping) } logrus.Infof("Images mapped") }
func (i *ImageMapping) MatchName(input string) bool { if input == i.ApiUUID { return true } if fuzzy.RankMatch(i.ManifestName, input) > -1 { return true } return false }
func (i *ImageMapping) MatchName(input string) bool { if input == i.ApiUUID { return true } input = ImageCodeName(input) if fuzzy.RankMatch(input, ImageCodeName(i.ManifestName)) > -1 { return true } for _, tag := range i.Objects.Manifest.Tags { nameWithTag := ImageCodeName(fmt.Sprintf("%s-%s", i.Objects.Manifest.Name, tag)) if fuzzy.RankMatch(input, nameWithTag) > -1 { return true } } return false }
// fSearchSnippet matches pattern to snippet name in SnippetSlice // returnes SnippetSlice of best matched snippets. func fSearchSnippet(snippets SnippetSlice, pattern string) (matched SnippetSlice) { topRank := 100 for _, s := range snippets { r := fuzzy.RankMatch(pattern, s.Name) switch { case r == topRank: matched = append(matched, s) case r != -1 && r < topRank: matched = SnippetSlice{s} topRank = r } } return matched }
// ComputeRankMatch fills `ScalewayResolverResult.RankMatch` with its `fuzzy` score func (s *ScalewayResolverResult) ComputeRankMatch(needle string) { s.Needle = needle s.RankMatch = fuzzy.RankMatch(needle, s.Name) }
// RunImages is the handler for 'scw images' func RunImages(ctx CommandContext, args ImagesArgs) error { wg := sync.WaitGroup{} chEntries := make(chan api.ScalewayImageInterface) errChan := make(chan error, 10) var entries = []api.ScalewayImageInterface{} filterType := args.Filters["type"] if filterType == "" || filterType == "image" { wg.Add(1) go func() { defer wg.Done() images, err := ctx.API.GetImages() if err != nil { errChan <- fmt.Errorf("unable to fetch images from the Scaleway API: %v", err) return } for _, val := range *images { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { errChan <- fmt.Errorf("unable to parse creation date from the Scaleway API: %v", err) return } archs := []string{} for _, version := range val.Versions { if val.CurrentPublicVersion == version.ID { for _, local := range version.LocalImages { archs = append(archs, local.Arch) } break } } chEntries <- api.ScalewayImageInterface{ Type: "image", CreationDate: creationDate, Identifier: val.CurrentPublicVersion, Name: val.Name, Tag: "latest", Organization: val.Organization.ID, Public: val.Public, // FIXME the region should not be hardcoded Region: "fr-1", Archs: archs, } } }() } if args.All || filterType != "" { if filterType == "" || filterType == "snapshot" { wg.Add(1) go func() { defer wg.Done() snapshots, err := ctx.API.GetSnapshots() if err != nil { errChan <- fmt.Errorf("unable to fetch snapshots from the Scaleway API: %v", err) return } for _, val := range *snapshots { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { errChan <- fmt.Errorf("unable to parse creation date from the Scaleway API: %v", err) return } chEntries <- api.ScalewayImageInterface{ Type: "snapshot", CreationDate: creationDate, Identifier: val.Identifier, Name: val.Name, Tag: "<snapshot>", VirtualSize: float64(val.Size), Public: false, Organization: val.Organization, // FIXME the region should not be hardcoded Region: "fr-1", } } }() } if filterType == "" || filterType == "bootscript" { wg.Add(1) go func() { defer wg.Done() bootscripts, err := ctx.API.GetBootscripts() if err != nil { errChan <- fmt.Errorf("unable to fetch bootscripts from the Scaleway API: %v", err) return } for _, val := range *bootscripts { chEntries <- api.ScalewayImageInterface{ Type: "bootscript", Identifier: val.Identifier, Name: val.Title, Tag: "<bootscript>", Public: false, // FIXME the region should not be hardcoded Region: "fr-1", Archs: []string{val.Arch}, } } }() } if filterType == "" || filterType == "volume" { wg.Add(1) go func() { defer wg.Done() volumes, err := ctx.API.GetVolumes() if err != nil { errChan <- fmt.Errorf("unable to fetch volumes from the Scaleway API: %v", err) return } for _, val := range *volumes { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { errChan <- fmt.Errorf("unable to parse creation date from the Scaleway API: %v", err) return } chEntries <- api.ScalewayImageInterface{ Type: "volume", CreationDate: creationDate, Identifier: val.Identifier, Name: val.Name, Tag: "<volume>", VirtualSize: float64(val.Size), Public: false, Organization: val.Organization, // FIXME the region should not be hardcoded Region: "fr-1", } } }() } } go func() { wg.Wait() close(chEntries) }() for { if entry, ok := <-chEntries; !ok { break } else { entries = append(entries, entry) } } select { case err := <-errChan: return err default: break } for key, value := range args.Filters { switch key { case "organization", "type", "name", "public": continue default: logrus.Warnf("Unknown filter: '%s=%s'", key, value) } } w := tabwriter.NewWriter(ctx.Stdout, 20, 1, 3, ' ', 0) defer w.Flush() if !args.Quiet { fmt.Fprintf(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tREGION\tARCH\n") } sort.Sort(api.ByCreationDate(entries)) for _, image := range entries { if image.Identifier == "" { continue } for key, value := range args.Filters { switch key { case "type": if value != image.Type { goto skipimage } case "organization": switch value { case "me": value = ctx.API.Organization case "official-distribs": value = "a283af0b-d13e-42e1-a43f-855ffbf281ab" case "official-apps": value = "c3884e19-7a3e-4b69-9db8-50e7f902aafc" } if image.Organization != value { goto skipimage } case "name": if fuzzy.RankMatch(strings.ToLower(value), strings.ToLower(image.Name)) == -1 { goto skipimage } case "public": if (value == "true" && !image.Public) || (value == "false" && image.Public) { goto skipimage } } } if args.Quiet { fmt.Fprintf(ctx.Stdout, "%s\n", image.Identifier) } else { tag := image.Tag shortID := utils.TruncIf(image.Identifier, 8, !args.NoTrunc) name := utils.Wordify(image.Name) if !image.Public && image.Type == "image" { name = "user/" + name } shortName := utils.TruncIf(name, 25, !args.NoTrunc) var creationDate string if image.CreationDate.IsZero() { creationDate = "n/a" } else { creationDate = units.HumanDuration(time.Now().UTC().Sub(image.CreationDate)) } if len(image.Archs) == 0 { image.Archs = []string{"n/a"} } sort.Strings(image.Archs) fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%v\n", shortName, tag, shortID, creationDate, image.Region, image.Archs) } skipimage: continue } return nil }
// RunPs is the handler for 'scw ps' func RunPs(ctx CommandContext, args PsArgs) error { limit := args.NLast if args.Latest { limit = 1 } filterState := args.Filters["state"] // FIXME: if filter state is defined, try to optimize the query all := args.All || limit > 0 || filterState != "" servers, err := ctx.API.GetServers(all, 0) if err != nil { return fmt.Errorf("Unable to fetch servers from the Scaleway API: %v", err) } for key, value := range args.Filters { switch key { case "state", "name", "tags", "image", "ip", "arch", "server-type", "zone": continue default: logrus.Warnf("Unknown filter: '%s=%s'", key, value) } } filtered := make([]api.ScalewayServer, 0, len(*servers)) for _, server := range *servers { // filtering for key, value := range args.Filters { switch key { case "state": if value != server.State { goto skipServer } case "name": if fuzzy.RankMatch(strings.ToLower(value), strings.ToLower(server.Name)) == -1 { goto skipServer } case "tags": found := false for _, tag := range server.Tags { if tag == value { found = true continue } } if !found { goto skipServer } case "image": imageID, err := ctx.API.GetImageID(value, "*") if err != nil { goto skipServer } if imageID.Identifier != server.Image.Identifier { goto skipServer } case "ip": if value != server.PublicAddress.IP { goto skipServer } case "arch": if value != server.Arch { goto skipServer } case "server-type": if value != server.CommercialType { goto skipServer } case "zone": if value != server.Location.ZoneID { goto skipServer } } } filtered = append(filtered, server) skipServer: continue } w := tabwriter.NewWriter(ctx.Stdout, 20, 1, 3, ' ', 0) defer w.Flush() if !args.Quiet { fmt.Fprintf(w, "SERVER ID\tIMAGE\tZONE\tCREATED\tSTATUS\tPORTS\tNAME\tCOMMERCIAL TYPE\n") } sort.Sort(api.ScalewaySortServers(filtered)) for i, server := range filtered { if limit > 0 && i >= limit { break } if args.Quiet { fmt.Fprintf(w, "%s\n", server.Identifier) } else { shortID := utils.TruncIf(server.Identifier, 8, !args.NoTrunc) shortImage := utils.TruncIf(utils.Wordify(server.Image.Name), 25, !args.NoTrunc) shortName := utils.TruncIf(utils.Wordify(server.Name), 25, !args.NoTrunc) creationTime, _ := time.Parse("2006-01-02T15:04:05.000000+00:00", server.CreationDate) shortCreationDate := units.HumanDuration(time.Now().UTC().Sub(creationTime)) port := server.PublicAddress.IP fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", shortID, shortImage, server.Location.ZoneID, shortCreationDate, server.State, port, shortName, server.CommercialType) } } return nil }