Beispiel #1
0
// LookUpServers attempts to return identifiers matching a pattern
func (c *ScalewayCache) LookUpServers(needle string, acceptUUID bool) ScalewayResolverResults {
	c.Lock.Lock()
	defer c.Lock.Unlock()

	var res ScalewayResolverResults

	if acceptUUID && anonuuid.IsUUID(needle) == nil {
		if fields, ok := c.Servers[needle]; ok {
			entry := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierServer)
			entry.ComputeRankMatch(needle)
			res = append(res, entry)
		}
	}

	nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
	var exactMatches ScalewayResolverResults
	for identifier, fields := range c.Servers {
		if fields[CacheTitle] == needle {
			entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierServer)
			entry.ComputeRankMatch(needle)
			exactMatches = append(exactMatches, entry)
		}
		if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) {
			entry := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierServer)
			entry.ComputeRankMatch(needle)
			res = append(res, entry)
		}
	}

	if len(exactMatches) == 1 {
		return exactMatches
	}

	return removeDuplicatesResults(res)
}
Beispiel #2
0
// RunTag is the handler for 'scw tag'
func RunTag(ctx CommandContext, args TagArgs) error {
	snapshotID, err := ctx.API.GetSnapshotID(args.Snapshot)
	if err != nil {
		return err
	}
	snapshot, err := ctx.API.GetSnapshot(snapshotID)
	if err != nil {
		return fmt.Errorf("cannot fetch snapshot: %v", err)
	}

	bootscriptID := ""
	if args.Bootscript != "" {
		if anonuuid.IsUUID(args.Bootscript) == nil {
			bootscriptID = args.Bootscript
		} else {
			bootscriptID, err = ctx.API.GetBootscriptID(args.Bootscript, args.Arch)
			if err != nil {
				return err
			}
		}
	}
	image, err := ctx.API.PostImage(snapshot.Identifier, args.Name, bootscriptID, args.Arch)
	if err != nil {
		return fmt.Errorf("cannot create image: %v", err)
	}
	fmt.Fprintln(ctx.Stdout, image)
	return nil
}
Beispiel #3
0
func shouldBeAnUUID(actual interface{}, expected ...interface{}) string {
	input := actual.(string)
	input = strings.TrimSpace(input)
	if err := anonuuid.IsUUID(input); err != nil {
		return fmt.Sprintf("%q should be an UUID", actual)
	}
	return ""
}
Beispiel #4
0
// NewScalewayResolverResult returns a new ScalewayResolverResult
func NewScalewayResolverResult(Identifier, Name, Arch string, Type int) ScalewayResolverResult {
	if err := anonuuid.IsUUID(Identifier); err != nil {
		log.Fatal(err)
	}
	return ScalewayResolverResult{
		Identifier: Identifier,
		Type:       Type,
		Name:       Name,
		Arch:       Arch,
	}
}
Beispiel #5
0
// NewScalewayResolverResult returns a new ScalewayResolverResult
func NewScalewayResolverResult(Identifier, Name, Arch string, Type int) (ScalewayResolverResult, error) {
	if err := anonuuid.IsUUID(Identifier); err != nil {
		return ScalewayResolverResult{}, err
	}
	return ScalewayResolverResult{
		Identifier: Identifier,
		Type:       Type,
		Name:       Name,
		Arch:       Arch,
	}, nil
}
Beispiel #6
0
// LookUpImages attempts to return identifiers matching a pattern
func (c *ScalewayCache) LookUpImages(needle string, acceptUUID bool) (ScalewayResolverResults, error) {
	c.Lock.Lock()
	defer c.Lock.Unlock()

	var res ScalewayResolverResults
	var exactMatches ScalewayResolverResults

	if acceptUUID && anonuuid.IsUUID(needle) == nil {
		if fields, ok := c.Images[needle]; ok {
			entry, err := NewScalewayResolverResult(needle, fields[CacheTitle], fields[CacheArch], IdentifierImage)
			if err != nil {
				return ScalewayResolverResults{}, err
			}
			entry.ComputeRankMatch(needle)
			res = append(res, entry)
		}
	}

	needle = regexp.MustCompile(`^user/`).ReplaceAllString(needle, "")
	// FIXME: if 'user/' is in needle, only watch for a user image
	nameRegex := regexp.MustCompile(`(?i)` + regexp.MustCompile(`[_-]`).ReplaceAllString(needle, ".*"))
	for identifier, fields := range c.Images {
		if fields[CacheTitle] == needle {
			entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierImage)
			if err != nil {
				return ScalewayResolverResults{}, err
			}
			entry.ComputeRankMatch(needle)
			exactMatches = append(exactMatches, entry)
		}
		if strings.HasPrefix(identifier, needle) || nameRegex.MatchString(fields[CacheTitle]) {
			entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierImage)
			if err != nil {
				return ScalewayResolverResults{}, err
			}
			entry.ComputeRankMatch(needle)
			res = append(res, entry)
		} else if strings.HasPrefix(fields[CacheMarketPlaceUUID], needle) || nameRegex.MatchString(fields[CacheMarketPlaceUUID]) {
			entry, err := NewScalewayResolverResult(identifier, fields[CacheTitle], fields[CacheArch], IdentifierImage)
			if err != nil {
				return ScalewayResolverResults{}, err
			}
			entry.ComputeRankMatch(needle)
			res = append(res, entry)
		}
	}

	if len(exactMatches) == 1 {
		return exactMatches, nil
	}

	return removeDuplicatesResults(res), nil
}
Beispiel #7
0
// CreateServer creates a server using API based on typical server fields
func CreateServer(api *ScalewayAPI, c *ConfigCreateServer) (string, error) {
	if c.CommercialType == "" {
		c.CommercialType = os.Getenv("SCW_COMMERCIAL_TYPE")
		if c.CommercialType == "" {
			c.CommercialType = "C1"
		}
	}

	if c.Name == "" {
		c.Name = strings.Replace(namesgenerator.GetRandomName(0), "_", "-", -1)
	}

	var server ScalewayServerDefinition

	server.CommercialType = c.CommercialType
	server.Volumes = make(map[string]string)
	server.DynamicIPRequired = &c.DynamicIPRequired
	if c.IP != "" {
		if anonuuid.IsUUID(c.IP) == nil {
			server.PublicIP = c.IP
		} else {
			ips, err := api.GetIPS()
			if err != nil {
				return "", err
			}
			for _, ip := range ips.IPS {
				if ip.Address == c.IP {
					server.PublicIP = ip.ID
					break
				}
			}
			if server.PublicIP == "" {
				return "", fmt.Errorf("IP address %v not found", c.IP)
			}
		}
	}
	server.Tags = []string{}
	if c.Env != "" {
		server.Tags = strings.Split(c.Env, " ")
	}
	if c.AdditionalVolumes != "" {
		volumes := strings.Split(c.AdditionalVolumes, " ")
		for i := range volumes {
			volumeID, err := CreateVolumeFromHumanSize(api, volumes[i])
			if err != nil {
				return "", err
			}

			volumeIDx := fmt.Sprintf("%d", i+1)
			server.Volumes[volumeIDx] = *volumeID
		}
	}
	// FIXME build images only on ARM ?
	imageIdentifier := &ScalewayImageIdentifier{
		Arch:   "arm",
		Region: "fr-1",
	}
	server.Name = c.Name
	inheritingVolume := false
	_, err := humanize.ParseBytes(c.ImageName)
	if err == nil {
		// Create a new root volume
		volumeID, err := CreateVolumeFromHumanSize(api, c.ImageName)
		if err != nil {
			return "", err
		}
		server.Volumes["0"] = *volumeID
	} else {
		// Use an existing image
		// FIXME: handle snapshots
		inheritingVolume = true
		imageIdentifier, err = api.GetImageID(c.ImageName)
		if err != nil {
			return "", err
		}
		if imageIdentifier.Identifier != "" {
			server.Image = &imageIdentifier.Identifier
		} else {
			snapshotID, err := api.GetSnapshotID(c.ImageName)
			if err != nil {
				return "", err
			}
			snapshot, err := api.GetSnapshot(snapshotID)
			if err != nil {
				return "", err
			}
			if snapshot.BaseVolume.Identifier == "" {
				return "", fmt.Errorf("snapshot %v does not have base volume", snapshot.Name)
			}
			server.Volumes["0"] = snapshot.BaseVolume.Identifier
		}
	}
	if c.Bootscript != "" {
		bootscript, err := api.GetBootscriptID(c.Bootscript, imageIdentifier.Arch)
		if err != nil {
			return "", err
		}
		server.Bootscript = &bootscript
	}
	serverID, err := api.PostServer(server)
	if err != nil {
		return "", err
	}

	// For inherited volumes, we prefix the name with server hostname
	if inheritingVolume {
		createdServer, err := api.GetServer(serverID)
		if err != nil {
			return "", err
		}
		currentVolume := createdServer.Volumes["0"]

		var volumePayload ScalewayVolumePutDefinition
		newName := fmt.Sprintf("%s-%s", createdServer.Hostname, currentVolume.Name)
		volumePayload.Name = &newName
		volumePayload.CreationDate = &currentVolume.CreationDate
		volumePayload.Organization = &currentVolume.Organization
		volumePayload.Server.Identifier = &currentVolume.Server.Identifier
		volumePayload.Server.Name = &currentVolume.Server.Name
		volumePayload.Identifier = &currentVolume.Identifier
		volumePayload.Size = &currentVolume.Size
		volumePayload.ModificationDate = &currentVolume.ModificationDate
		volumePayload.ExportURI = &currentVolume.ExportURI
		volumePayload.VolumeType = &currentVolume.VolumeType

		err = api.PutVolume(currentVolume.Identifier, volumePayload)
		if err != nil {
			return "", err
		}
	}

	return serverID, nil
}
Beispiel #8
0
// CreateServer creates a server using API based on typical server fields
func CreateServer(api *ScalewayAPI, c *ConfigCreateServer) (string, error) {
	commercialType := os.Getenv("SCW_COMMERCIAL_TYPE")
	if commercialType == "" {
		commercialType = c.CommercialType
	}
	if len(commercialType) < 2 {
		return "", errors.New("Invalid commercial type")
	}

	if c.Name == "" {
		c.Name = strings.Replace(namesgenerator.GetRandomName(0), "_", "-", -1)
	}

	var server ScalewayServerDefinition

	server.CommercialType = commercialType
	server.Volumes = make(map[string]string)
	server.DynamicIPRequired = &c.DynamicIPRequired
	server.EnableIPV6 = c.EnableIPV6
	if commercialType == "" {
		return "", errors.New("You need to specify a commercial-type")
	}
	if c.IP != "" {
		if anonuuid.IsUUID(c.IP) == nil {
			server.PublicIP = c.IP
		} else {
			ips, err := api.GetIPS()
			if err != nil {
				return "", err
			}
			for _, ip := range ips.IPS {
				if ip.Address == c.IP {
					server.PublicIP = ip.ID
					break
				}
			}
			if server.PublicIP == "" {
				return "", fmt.Errorf("IP address %v not found", c.IP)
			}
		}
	}
	server.Tags = []string{}
	if c.Env != "" {
		server.Tags = strings.Split(c.Env, " ")
	}
	switch c.CommercialType {
	case "VC1M":
		if c.AdditionalVolumes == "" {
			c.AdditionalVolumes = "50G"
			log.Debugf("This server needs a least 50G")
		}
	case "VC1L":
		if c.AdditionalVolumes == "" {
			c.AdditionalVolumes = "150G"
			log.Debugf("This server needs a least 150G")
		}
	}
	if c.AdditionalVolumes != "" {
		volumes := strings.Split(c.AdditionalVolumes, " ")
		for i := range volumes {
			volumeID, err := CreateVolumeFromHumanSize(api, volumes[i])
			if err != nil {
				return "", err
			}

			volumeIDx := fmt.Sprintf("%d", i+1)
			server.Volumes[volumeIDx] = *volumeID
		}
	}
	arch := os.Getenv("SCW_TARGET_ARCH")
	if arch == "" {
		server.CommercialType = strings.ToUpper(server.CommercialType)
		switch server.CommercialType[:2] {
		case "C1":
			arch = "arm"
		case "C2", "VC":
			arch = "x86_64"
		default:
			return "", fmt.Errorf("%s wrong commercial type", server.CommercialType)
		}
	}
	region := os.Getenv("SCW_TARGET_REGION")
	if region == "" {
		region = "fr-1"
	}
	imageIdentifier := &ScalewayImageIdentifier{
		Arch:   arch,
		Region: region,
	}
	server.Name = c.Name
	inheritingVolume := false
	_, err := humanize.ParseBytes(c.ImageName)
	if err == nil {
		// Create a new root volume
		volumeID, errCreateVol := CreateVolumeFromHumanSize(api, c.ImageName)
		if errCreateVol != nil {
			return "", errCreateVol
		}
		server.Volumes["0"] = *volumeID
	} else {
		// Use an existing image
		inheritingVolume = true
		if anonuuid.IsUUID(c.ImageName) == nil {
			server.Image = &c.ImageName
		} else {
			imageIdentifier, err = api.GetImageID(c.ImageName, arch)
			if err != nil {
				return "", err
			}
			if imageIdentifier.Identifier != "" {
				server.Image = &imageIdentifier.Identifier
			} else {
				snapshotID, errGetSnapID := api.GetSnapshotID(c.ImageName)
				if errGetSnapID != nil {
					return "", errGetSnapID
				}
				snapshot, errGetSnap := api.GetSnapshot(snapshotID)
				if errGetSnap != nil {
					return "", errGetSnap
				}
				if snapshot.BaseVolume.Identifier == "" {
					return "", fmt.Errorf("snapshot %v does not have base volume", snapshot.Name)
				}
				server.Volumes["0"] = snapshot.BaseVolume.Identifier
			}
		}
	}

	if c.Bootscript != "" {
		bootscript := ""

		if anonuuid.IsUUID(c.Bootscript) == nil {
			bootscript = c.Bootscript
		} else {
			var errGetBootScript error

			bootscript, errGetBootScript = api.GetBootscriptID(c.Bootscript, imageIdentifier.Arch)
			if errGetBootScript != nil {
				return "", errGetBootScript
			}
		}
		server.Bootscript = &bootscript
	}
	serverID, err := api.PostServer(server)
	if err != nil {
		return "", err
	}

	// For inherited volumes, we prefix the name with server hostname
	if inheritingVolume {
		createdServer, err := api.GetServer(serverID)
		if err != nil {
			return "", err
		}
		currentVolume := createdServer.Volumes["0"]
		size := uint64(currentVolume.Size.(float64))

		var volumePayload ScalewayVolumePutDefinition
		newName := fmt.Sprintf("%s-%s", createdServer.Hostname, currentVolume.Name)
		volumePayload.Name = &newName
		volumePayload.CreationDate = &currentVolume.CreationDate
		volumePayload.Organization = &currentVolume.Organization
		volumePayload.Server.Identifier = &currentVolume.Server.Identifier
		volumePayload.Server.Name = &currentVolume.Server.Name
		volumePayload.Identifier = &currentVolume.Identifier
		volumePayload.Size = &size
		volumePayload.ModificationDate = &currentVolume.ModificationDate
		volumePayload.ExportURI = &currentVolume.ExportURI
		volumePayload.VolumeType = &currentVolume.VolumeType

		err = api.PutVolume(currentVolume.Identifier, volumePayload)
		if err != nil {
			return "", err
		}
	}

	return serverID, nil
}