Просмотр исходного кода

Adding in the stubs for GCP Reserved Instances. This is tested to be working correctly, but does not apply discounts yet. Commented code for AWS, but will be similar. There are some issues with Global discount that we need to refactor in order to get this partially working.

Matt Bolt 6 лет назад
Родитель
Сommit
ec8a428df2
2 измененных файлов с 159 добавлено и 0 удалено
  1. 39 0
      cloud/awsprovider.go
  2. 120 0
      cloud/gcpprovider.go

+ 39 - 0
cloud/awsprovider.go

@@ -1401,3 +1401,42 @@ func parseSpotData(bucket string, prefix string, projectID string, region string
 	}
 	}
 	return spots, nil
 	return spots, nil
 }
 }
+
+/*
+func (aws *AWS) getReservedInstances() ([]interface{}, error) {
+	customPricing, err := a.GetConfig()
+	if err != nil {
+		return nil, err
+	}
+	if customPricing.ServiceKeyName != "" {
+		err = os.Setenv(awsAccessKeyIDEnvVar, customPricing.ServiceKeyName)
+		if err != nil {
+			return nil, err
+		}
+		err = os.Setenv(awsAccessKeySecretEnvVar, customPricing.ServiceKeySecret)
+		if err != nil {
+			return nil, err
+		}
+	}
+	athenaConfigs, err := os.Open("/var/configs/athena.json")
+	if err != nil {
+		return nil, err
+	}
+	defer athenaConfigs.Close()
+	b, err := ioutil.ReadAll(athenaConfigs)
+	if err != nil {
+		return nil, err
+	}
+	var athenaConf map[string]string
+	json.Unmarshal([]byte(b), &athenaConf)
+	region := aws.String(customPricing.AthenaRegion)
+
+	c := &aws.Config{
+		Region: region,
+	}
+	s := session.Must(session.NewSession(c))
+	svc := ec2.New(s)
+
+	svc.DescribeReservedInstances()
+}
+*/

+ 120 - 0
cloud/gcpprovider.go

@@ -14,6 +14,7 @@ import (
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
+	"time"
 
 
 	"k8s.io/klog"
 	"k8s.io/klog"
 
 
@@ -704,6 +705,16 @@ func (gcp *GCP) DownloadPricingData() error {
 		pvkeys[key.Features()] = key
 		pvkeys[key.Features()] = key
 	}
 	}
 
 
+	reserved, err := gcp.getReservedInstances()
+	if err != nil {
+		klog.V(1).Infof("Failed to lookup reserved instance data: %s", err.Error())
+	} else {
+		klog.V(1).Infof("Found %d reserved instances", len(reserved))
+		for _, r := range reserved {
+			klog.V(1).Infof("Reserved: CPU: %d, RAM: %d", r.ReservedCPU, r.ReservedRAM)
+		}
+	}
+
 	pages, err := gcp.parsePages(inputkeys, pvkeys)
 	pages, err := gcp.parsePages(inputkeys, pvkeys)
 
 
 	if err != nil {
 	if err != nil {
@@ -750,6 +761,115 @@ func (c *GCP) NetworkPricing() (*Network, error) {
 	}, nil
 	}, nil
 }
 }
 
 
+const (
+	GCPReservedInstanceResourceTypeRAM string = "MEMORY"
+	GCPReservedInstanceResourceTypeCPU string = "VCPU"
+	GCPReservedInstanceStatusActive    string = "ACTIVE"
+	GCPReservedInstancePlanOneYear     string = "TWELVE_MONTH"
+	GCPReservedInstancePlanThreeYear   string = "THIRTY_SIX_MONTH"
+)
+
+type GCPReservedInstancePlan struct {
+	Name    string
+	CPUCost float64
+	RAMCost float64
+}
+
+type GCPReservedInstance struct {
+	ReservedRAM int64
+	ReservedCPU int64
+	Plan        *GCPReservedInstancePlan
+	StartDate   time.Time
+	EndDate     time.Time
+	Region      string
+}
+
+// Two available Reservation plans for GCP, 1-year and 3-year
+var gcpReservedInstancePlans map[string]*GCPReservedInstancePlan = map[string]*GCPReservedInstancePlan{
+	GCPReservedInstancePlanOneYear: &GCPReservedInstancePlan{
+		Name:    GCPReservedInstancePlanOneYear,
+		CPUCost: 0.019915,
+		RAMCost: 0.002669,
+	},
+	GCPReservedInstancePlanThreeYear: &GCPReservedInstancePlan{
+		Name:    GCPReservedInstancePlanThreeYear,
+		CPUCost: 0.014225,
+		RAMCost: 0.001907,
+	},
+}
+
+func (gcp *GCP) getReservedInstances() ([]*GCPReservedInstance, error) {
+	var results []*GCPReservedInstance
+
+	ctx := context.Background()
+	computeService, err := compute.NewService(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	commitments, err := computeService.RegionCommitments.AggregatedList(gcp.ProjectID).Do()
+	if err != nil {
+		return nil, err
+	}
+
+	for regionKey, commitList := range commitments.Items {
+		for _, commit := range commitList.Commitments {
+			if commit.Status != GCPReservedInstanceStatusActive {
+				continue
+			}
+
+			var vcpu int64 = 0
+			var ram int64 = 0
+			for _, resource := range commit.Resources {
+				switch resource.Type {
+				case GCPReservedInstanceResourceTypeRAM:
+					ram = resource.Amount
+				case GCPReservedInstanceResourceTypeCPU:
+					vcpu = resource.Amount
+				default:
+					klog.V(4).Infof("Failed to handle resource type: %s", resource.Type)
+				}
+			}
+
+			var region string
+			regionStr := strings.Split(regionKey, "/")
+			if len(regionStr) == 2 {
+				region = regionStr[1]
+			}
+
+			timeLayout := "2006-01-02T15:04:05Z07:00"
+			startTime, err := time.Parse(timeLayout, commit.StartTimestamp)
+			if err != nil {
+				klog.V(1).Infof("Failed to parse start date: %s", commit.StartTimestamp)
+				continue
+			}
+
+			endTime, err := time.Parse(timeLayout, commit.EndTimestamp)
+			if err != nil {
+				klog.V(1).Infof("Failed to parse end date: %s", commit.EndTimestamp)
+				continue
+			}
+
+			// Look for a plan based on the name. Default to One Year if it fails
+			plan, ok := gcpReservedInstancePlans[commit.Plan]
+			if !ok {
+				plan = gcpReservedInstancePlans[GCPReservedInstancePlanOneYear]
+			}
+
+			results = append(results, &GCPReservedInstance{
+				Region:      region,
+				ReservedRAM: ram,
+				ReservedCPU: vcpu,
+				Plan:        plan,
+				StartDate:   startTime,
+				EndDate:     endTime,
+			})
+		}
+	}
+
+	return results, nil
+}
+
 type pvKey struct {
 type pvKey struct {
 	Labels                 map[string]string
 	Labels                 map[string]string
 	StorageClass           string
 	StorageClass           string