123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- package cloud
- import (
- "context"
- "errors"
- "fmt"
- "strconv"
- "strings"
- "time"
- "git.linuxforward.com/byop/byop-engine/models"
- "github.com/ovh/go-ovh/ovh"
- "github.com/sirupsen/logrus"
- )
- // OVHProvider implements the Provider interface for OVH Cloud
- type OVHProvider struct {
- entry *logrus.Entry
- client *ovh.Client
- region string
- configured bool
- }
- // NewOVHProvider creates a new OVH provider
- func NewOVHProvider() Provider {
- return &OVHProvider{
- entry: logrus.WithField("provider", "ovh"),
- }
- }
- func init() {
- RegisterProvider("ovh", NewOVHProvider)
- }
- // Initialize sets up the OVH provider with credentials and configuration
- func (p *OVHProvider) Initialize(config map[string]string) error {
- // Check required configuration
- requiredKeys := []string{"client_id", "client_secret", "endpoint"}
- for _, key := range requiredKeys {
- if _, ok := config[key]; !ok {
- return fmt.Errorf("missing required configuration key: %s", key)
- }
- }
- // Create OVH client
- client, err := ovh.NewOAuth2Client(
- config["endpoint"],
- config["client_id"],
- config["client_secret"],
- )
- if err != nil {
- return fmt.Errorf("failed to create OVH client: %w", err)
- }
- // Test the client by trying to list VPS IDs
- var vpsIDs []string
- if err = client.Get("/vps", &vpsIDs); err != nil {
- return fmt.Errorf("failed to connect to OVH API: %w", err)
- }
- // Set client before testing VPS connectivity
- p.client = client
- p.configured = true
- // Set region if provided
- if region, ok := config["region"]; ok {
- p.region = region
- }
- p.entry.Info("OVH provider initialized")
- return nil
- }
- // ListRegions lists all available OVH regions
- func (p *OVHProvider) ListRegions(ctx context.Context) ([]Region, error) {
- if !p.configured {
- return nil, errors.New("provider not configured")
- }
- type OVHRegion struct {
- AvailabilityZones []string `json:"availabilityZones"`
- CardinalPoint string `json:"cardinalPoint"`
- CityCode string `json:"cityCode"`
- CityLatitude float64 `json:"cityLatitude"`
- CityLongitude float64 `json:"cityLongitude"`
- CityName string `json:"cityName"`
- Code string `json:"code"`
- CountryCode string `json:"countryCode"`
- CountryName string `json:"countryName"`
- GeographyCode string `json:"geographyCode"`
- GeographyName string `json:"geographyName"`
- Location string `json:"location"`
- Name string `json:"name"`
- OpeningYear int `json:"openingYear"`
- SpecificType string `json:"specificType"`
- Type string `json:"type"`
- }
- // Get the list of regions from OVH
- path := "/v2/location"
- var regions []Region
- var ovhRegions []OVHRegion
- err := p.client.Get(path, &ovhRegions)
- if err != nil {
- return nil, fmt.Errorf("failed to list regions: %w", err)
- }
- fmt.Printf("OVH regions: %v\n", ovhRegions)
- // Convert OVHRegion to Region
- for _, ovhRegion := range ovhRegions {
- regions = append(regions, Region{
- ID: ovhRegion.Name,
- Zone: strings.Join(ovhRegion.AvailabilityZones, ","),
- // Add other fields as needed
- })
- }
- return regions, nil
- }
- // ListInstanceSizes lists available VM sizes (flavors) in OVH
- func (p *OVHProvider) ListInstanceSizes(ctx context.Context, region string) ([]InstanceSize, error) {
- // TODO: Implement this method
- return nil, errors.New("not implemented")
- }
- // ListInstances lists all instances in OVH
- func (p *OVHProvider) ListInstances(ctx context.Context) ([]Instance, error) {
- if !p.configured {
- return nil, errors.New("provider not configured")
- }
- path := "/vps"
- var vpsIDs []string
- var vpsList []*models.OVHVPS
- err := p.client.Get(path, &vpsIDs)
- if err != nil {
- return nil, fmt.Errorf("failed to list instances: %w", err)
- }
- // Get details for each VPS ID
- for _, vpsID := range vpsIDs {
- path := fmt.Sprintf("/vps/%s", vpsID)
- vps := &models.OVHVPS{}
- err := p.client.Get(path, vps)
- if err != nil {
- return nil, fmt.Errorf("failed to get instance %s: %w", vpsID, err)
- }
- vpsList = append(vpsList, vps)
- }
- instances := make([]Instance, len(vpsList))
- for i, vps := range vpsList {
- // convert size
- instances[i] = Instance{
- ID: vps.Name,
- Name: vps.DisplayName,
- Region: vps.Zone,
- Size: strconv.Itoa(vps.VCore),
- Status: vps.State,
- }
- }
- return instances, nil
- }
- // ResetInstance resets an instance in OVH
- func (p *OVHProvider) ResetInstance(ctx context.Context, id string) error {
- // TODO: Implement this method
- return errors.New("not implemented")
- }
- // StartInstance starts an instance in OVH
- func (p *OVHProvider) StartInstance(ctx context.Context, id string) error {
- // TODO: Implement this method
- return errors.New("not implemented")
- }
- // StopInstance stops an instance in OVH
- func (p *OVHProvider) StopInstance(ctx context.Context, id string) error {
- // TODO: Implement this method
- return errors.New("not implemented")
- }
- // RestartInstance restarts an instance in OVH
- func (p *OVHProvider) RestartInstance(ctx context.Context, id string) error {
- // TODO: Implement this method
- return errors.New("not implemented")
- }
- // WaitForInstanceStatus waits for an instance to reach a specific status
- func (p *OVHProvider) WaitForInstanceStatus(ctx context.Context, id, status string, timeout time.Duration) error {
- // TODO: Implement this method
- return errors.New("not implemented")
- }
- // GetFirstFreeInstance retrieves the first available instance
- func (p *OVHProvider) GetFirstFreeInstance(ctx context.Context) (*Instance, error) {
- // List all instances
- instances, err := p.ListInstances(ctx)
- if err != nil {
- return nil, fmt.Errorf("failed to list instances: %w", err)
- }
- // Iterate through instances to find the first free one
- for _, instance := range instances {
- // This will be final optioons using tags
- // Check if instance has tags and if the instance is marked as available
- // if instance.DisplayName != nil && instance.Tags["byop-state"] == "available" {
- // // Get full details of the instance
- // vpsPath := fmt.Sprintf("/vps/%s", instance.ID)
- // vps := &models.OVHVPS{}
- // err := p.client.Get(vpsPath, vps)
- // if err != nil {
- // // Log the error but continue with next instance
- // fmt.Printf("Error fetching details for VPS %s: %v\n", instance.ID, err)
- // continue
- // }
- // return vps, nil
- // }
- // Check if display name contains byom.fr or byop.fr
- if instance.Name != "" && (strings.Contains(instance.Name, "byom.fr") || strings.Contains(instance.Name, "byop.fr")) {
- // Get full details of the instance
- vpsPath := fmt.Sprintf("/vps/%s", instance.ID)
- vps := &models.OVHVPS{}
- err := p.client.Get(vpsPath, vps)
- if err != nil {
- // Log the error but continue with next instance
- fmt.Printf("Error fetching details for VPS %s: %v\n", instance.ID, err)
- continue
- }
- // Mark this instance as in use
- if instance.Tags != nil {
- instance.Tags["byop-state"] = "in-use"
- }
- return &Instance{
- ID: vps.Name,
- Name: vps.DisplayName,
- IPAddress: vps.Name,
- Region: vps.Zone,
- Size: strconv.Itoa(vps.VCore),
- Status: vps.State,
- }, nil
- }
- }
- // If no instance with "available" tag is found, just return the first running instance
- // if len(instances) > 0 {
- // for _, instance := range instances {
- // if instance.Status == "Running" {
- // vpsPath := fmt.Sprintf("/vps/%s", instance.ID)
- // vps := &models.OVHVPS{}
- // err := p.client.Get(vpsPath, vps)
- // if err != nil {
- // // Log the error but continue
- // fmt.Printf("Error fetching details for VPS %s: %v\n", instance.ID, err)
- // continue
- // }
- // // Mark this instance as in use
- // if instance.Tags != nil {
- // instance.Tags["byop-state"] = "in-use"
- // }
- // return vps, nil
- // }
- // }
- // }
- // If no instances are found or none are available, return an error
- return nil, fmt.Errorf("no free instances found in OVH infrastructure")
- }
|