Пример #1
0
func wordifyName(name string, kind string) string {
	ret := ""
	if completionPrefix {
		ret += kind + "\\:"
	}
	ret += utils.Wordify(name)
	return ret
}
Пример #2
0
func runBilling(cmd *Command, rawArgs []string) error {
	if billingHelp {
		return cmd.PrintUsage()
	}
	if len(rawArgs) > 0 {
		return cmd.PrintShortUsage()
	}

	// cli parsing
	args := commands.PsArgs{
		NoTrunc: billingNoTrunc,
	}
	ctx := cmd.GetContext(rawArgs)

	logrus.Warn("")
	logrus.Warn("Warning: 'scw _billing' is a work-in-progress price estimation tool")
	logrus.Warn("For real usage, visit https://cloud.scaleway.com/#/billing")
	logrus.Warn("")

	// table
	w := tabwriter.NewWriter(ctx.Stdout, 20, 1, 3, ' ', 0)
	defer w.Flush()
	fmt.Fprintf(w, "ID\tNAME\tSTARTED\tMONTH PRICE\n")

	// servers
	servers, err := cmd.API.GetServers(true, 0)
	if err != nil {
		return err
	}

	totalMonthPrice := new(big.Rat)

	for _, server := range *servers {
		if server.State != "running" {
			continue
		}
		commercialType := strings.ToLower(server.CommercialType)
		shortID := utils.TruncIf(server.Identifier, 8, !args.NoTrunc)
		shortName := utils.TruncIf(utils.Wordify(server.Name), 25, !args.NoTrunc)
		modificationTime, _ := time.Parse("2006-01-02T15:04:05.000000+00:00", server.ModificationDate)
		modificationAgo := time.Now().UTC().Sub(modificationTime)
		shortModificationDate := units.HumanDuration(modificationAgo)
		usage := pricing.NewUsageByPath(fmt.Sprintf("/compute/%s/run", commercialType))
		usage.SetStartEnd(modificationTime, time.Now().UTC())

		totalMonthPrice = totalMonthPrice.Add(totalMonthPrice, usage.Total())

		fmt.Fprintf(w, "server/%s/%s\t%s\t%s\t%s\n", commercialType, shortID, shortName, shortModificationDate, usage.TotalString())
	}

	fmt.Fprintf(w, "TOTAL\t\t\t%s\n", pricing.PriceString(totalMonthPrice, "EUR"))

	return nil
}
Пример #3
0
// RunImages is the handler for 'scw images'
func RunImages(ctx CommandContext, args ImagesArgs) error {
	wg := sync.WaitGroup{}
	chEntries := make(chan api.ScalewayImageInterface)
	var entries = []api.ScalewayImageInterface{}

	filterType := args.Filters["type"]

	// FIXME: remove log.Fatalf in routines

	if filterType == "" || filterType == "image" {
		wg.Add(1)
		go func() {
			defer wg.Done()
			images, err := ctx.API.GetImages()
			if err != nil {
				logrus.Fatalf("unable to fetch images from the Scaleway API: %v", err)
			}
			for _, val := range *images {
				creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate)
				if err != nil {
					logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err)
				}
				chEntries <- api.ScalewayImageInterface{
					Type:         "image",
					CreationDate: creationDate,
					Identifier:   val.Identifier,
					Name:         val.Name,
					Public:       val.Public,
					Tag:          "latest",
					VirtualSize:  float64(val.RootVolume.Size),
					Organization: val.Organization,
				}
			}
		}()
	}

	if args.All || filterType != "" {
		if filterType == "" || filterType == "snapshot" {
			wg.Add(1)
			go func() {
				defer wg.Done()
				snapshots, err := ctx.API.GetSnapshots()
				if err != nil {
					logrus.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err)
				}
				for _, val := range *snapshots {
					creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate)
					if err != nil {
						logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err)
					}
					chEntries <- api.ScalewayImageInterface{
						Type:         "snapshot",
						CreationDate: creationDate,
						Identifier:   val.Identifier,
						Name:         val.Name,
						Tag:          "<snapshot>",
						VirtualSize:  float64(val.Size),
						Public:       false,
						Organization: val.Organization,
					}
				}
			}()
		}

		if filterType == "" || filterType == "bootscript" {
			wg.Add(1)
			go func() {
				defer wg.Done()
				bootscripts, err := ctx.API.GetBootscripts()
				if err != nil {
					logrus.Fatalf("unable to fetch bootscripts from the Scaleway API: %v", err)
				}
				for _, val := range *bootscripts {
					chEntries <- api.ScalewayImageInterface{
						Type:       "bootscript",
						Identifier: val.Identifier,
						Name:       val.Title,
						Tag:        "<bootscript>",
						Public:     false,
					}
				}
			}()
		}

		if filterType == "" || filterType == "volume" {
			wg.Add(1)
			go func() {
				defer wg.Done()
				volumes, err := ctx.API.GetVolumes()
				if err != nil {
					logrus.Fatalf("unable to fetch volumes from the Scaleway API: %v", err)
				}
				for _, val := range *volumes {
					creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate)
					if err != nil {
						logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err)
					}
					chEntries <- api.ScalewayImageInterface{
						Type:         "volume",
						CreationDate: creationDate,
						Identifier:   val.Identifier,
						Name:         val.Name,
						Tag:          "<volume>",
						VirtualSize:  float64(val.Size),
						Public:       false,
						Organization: val.Organization,
					}
				}
			}()
		}
	}

	go func() {
		wg.Wait()
		close(chEntries)
	}()

	done := false
	for {
		select {
		case entry, ok := <-chEntries:
			if !ok {
				done = true
				break
			}
			entries = append(entries, entry)
		}
		if done {
			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\tVIRTUAL SIZE\n")
	}
	sort.Sort(api.ByCreationDate(entries))
	for _, image := range entries {

		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, virtualSize string
			if image.CreationDate.IsZero() {
				creationDate = "n/a"
			} else {
				creationDate = units.HumanDuration(time.Now().UTC().Sub(image.CreationDate))
			}
			if image.VirtualSize == 0 {
				virtualSize = "n/a"
			} else {
				virtualSize = units.HumanSize(image.VirtualSize)
			}
			fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", shortName, tag, shortID, creationDate, virtualSize)
		}

	skipimage:
		continue
	}
	return nil
}
Пример #4
0
// RunSearch is the handler for 'scw search'
func RunSearch(ctx CommandContext, args SearchArgs) error {
	// FIXME: parallelize API calls

	term := strings.ToLower(args.Term)
	w := tabwriter.NewWriter(ctx.Stdout, 10, 1, 3, ' ', 0)
	defer w.Flush()
	fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n")

	var entries = []api.ScalewayImageInterface{}

	images, err := ctx.API.GetImages()
	if err != nil {
		return fmt.Errorf("unable to fetch images from the Scaleway API: %v", err)
	}
	for _, val := range *images {
		if fuzzy.Match(term, strings.ToLower(val.Name)) {
			entries = append(entries, api.ScalewayImageInterface{
				Type:   "image",
				Name:   val.Name,
				Public: val.Public,
			})
		}
	}

	snapshots, err := ctx.API.GetSnapshots()
	if err != nil {
		return fmt.Errorf("unable to fetch snapshots from the Scaleway API: %v", err)
	}
	for _, val := range *snapshots {
		if fuzzy.Match(term, strings.ToLower(val.Name)) {
			entries = append(entries, api.ScalewayImageInterface{
				Type:   "snapshot",
				Name:   val.Name,
				Public: false,
			})
		}
	}

	for _, image := range entries {
		// name field
		name := utils.TruncIf(utils.Wordify(image.Name), 45, !args.NoTrunc)

		// description field
		var description string
		switch image.Type {
		case "image":
			if image.Public {
				description = "public image"
			} else {
				description = "user image"
			}

		case "snapshot":
			description = "user snapshot"
		}
		description = utils.TruncIf(utils.Wordify(description), 45, !args.NoTrunc)

		// official field
		var official string
		if image.Public {
			official = "[OK]"
		} else {
			official = ""
		}

		fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\n", name, description, 0, official, "")
	}
	return nil
}
Пример #5
0
// 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 || args.NLast > 0 || args.Latest || filterState != ""
	servers, err := ctx.API.GetServers(all, limit)
	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":
			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, "SERVER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAME\n")
	}
	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 := ctx.API.GetImageID(value, true)
				if imageID != server.Image.Identifier {
					goto skipServer
				}
			case "ip":
				if value != server.PublicAddress.IP {
					goto skipServer
				}
			}
		}

		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\t%s\t%s\t%s\t%s\n", shortID, shortImage, shortCreationDate, server.State, port, shortName)
		}
	skipServer:
		continue
	}
	return nil
}
Пример #6
0
// 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
}