Skip to content

Commit

Permalink
ec2 refactor, unit test correction (#72)
Browse files Browse the repository at this point in the history
* ec2 prodsuct info related refactoring: session handling, reginos passed to the client

* fixes in test code, rename internal interface

* go fmt, lint , etc ...

* fixed struct field definition

* unit test correction for ec2 operations

* gofmt

* struct rename

* constant use of ec2 library
  • Loading branch information
prekoa authored and lpuskas committed Jun 14, 2018
1 parent 9fb4c59 commit 23acd4b
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 71 deletions.
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func infoers() map[string]productinfo.ProductInfoer {

switch p {
case recommender.Ec2:
infoer, err = ec2.NewEc2Infoer(ec2.NewPricing(ec2.NewConfig()), viper.GetString(prometheusAddressFlag), viper.GetString(prometheusQueryFlag))
infoer, err = ec2.NewEc2Infoer(viper.GetString(prometheusAddressFlag), viper.GetString(prometheusQueryFlag))
case recommender.Gce:
infoer, err = gce.NewGceInfoer(viper.GetString(gceApiKeyFlag), viper.GetString(gceProjectIdFlag))
case recommender.Azure:
Expand Down
55 changes: 27 additions & 28 deletions productinfo/ec2/productinfo_ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,34 @@ type PricingSource interface {

// Ec2Infoer encapsulates the data and operations needed to access external resources
type Ec2Infoer struct {
pricing PricingSource
session *session.Session
prometheus v1.API
promQuery string
pricingSvc PricingSource
session *session.Session
prometheus v1.API
promQuery string
ec2Describer func(region string) Ec2Describer
}

// Ec2Describer interface for operations describing EC2 artifacts. (a subset of the Ec2 cli operations iused by this app)
type Ec2Describer interface {
DescribeAvailabilityZones(input *ec2.DescribeAvailabilityZonesInput) (*ec2.DescribeAvailabilityZonesOutput, error)
DescribeSpotPriceHistoryPages(input *ec2.DescribeSpotPriceHistoryInput, fn func(*ec2.DescribeSpotPriceHistoryOutput, bool) bool) error
}

// NewEc2Infoer creates a new instance of the infoer
func NewEc2Infoer(pricing PricingSource, prom string, pq string) (*Ec2Infoer, error) {
func NewEc2Infoer(promAddr string, pq string) (*Ec2Infoer, error) {
s, err := session.NewSession()

if err != nil {
log.WithError(err).Error("Error creating AWS session")
return nil, err
}
var promApi v1.API
if prom == "" {
if promAddr == "" {
log.Warn("Prometheus API address is not set, fallback to direct API access.")
promApi = nil
} else {
promClient, err := api.NewClient(api.Config{
Address: prom,
Address: promAddr,
})
if err != nil {
log.WithError(err).Warn("Error creating Prometheus client, fallback to direct API access.")
Expand All @@ -66,29 +74,21 @@ func NewEc2Infoer(pricing PricingSource, prom string, pq string) (*Ec2Infoer, er
}
}

const defaultPricingRegion = "us-east-1"
return &Ec2Infoer{
pricing: pricing,
pricingSvc: pricing.New(s, aws.NewConfig().WithRegion(defaultPricingRegion)),
session: s,
prometheus: promApi,
promQuery: pq,
ec2Describer: func(region string) Ec2Describer {
return ec2.New(s, aws.NewConfig().WithRegion(region))
},
}, nil
}

// NewPricing creates a new PricingSource with the given configuration
func NewPricing(cfg *aws.Config) PricingSource {

s, err := session.NewSession(cfg)
if err != nil {
log.Fatalf("could not create session. error: [%s]", err.Error())
}

pr := pricing.New(s, cfg)
return pr
}

// NewConfig creates a new Config instance and returns a pointer to it
func NewConfig() *aws.Config {
return &aws.Config{Region: aws.String("us-east-1")}
return aws.NewConfig()
}

// Initialize is not needed on EC2 because price info is changing frequently
Expand All @@ -99,7 +99,7 @@ func (e *Ec2Infoer) Initialize() (map[string]map[string]productinfo.Price, error
// GetAttributeValues gets the AttributeValues for the given attribute name
// Delegates to the underlying PricingSource instance and unifies (transforms) the response
func (e *Ec2Infoer) GetAttributeValues(attribute string) (productinfo.AttrValues, error) {
apiValues, err := e.pricing.GetAttributeValues(e.newAttributeValuesInput(attribute))
apiValues, err := e.pricingSvc.GetAttributeValues(e.newAttributeValuesInput(attribute))
if err != nil {
return nil, err
}
Expand All @@ -126,7 +126,7 @@ func (e *Ec2Infoer) GetProducts(regionId string, attrKey string, attrValue produ
var vms []productinfo.VmInfo
log.Debugf("Getting available instance types from AWS API. [region=%s, %s=%s]", regionId, attrKey, attrValue.StrValue)

products, err := e.pricing.GetProducts(e.newGetProductsInput(regionId, attrKey, attrValue))
products, err := e.pricingSvc.GetProducts(e.newGetProductsInput(regionId, attrKey, attrValue))

if err != nil {
return nil, err
Expand Down Expand Up @@ -328,14 +328,14 @@ func (e *Ec2Infoer) GetRegions() (map[string]string, error) {

// GetZones returns the availability zones in a region
func (e *Ec2Infoer) GetZones(region string) ([]string, error) {

var zones []string
ec2Svc := ec2.New(e.session, &aws.Config{Region: aws.String(region)})
azs, err := ec2Svc.DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{})
azs, err := e.ec2Describer(region).DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{})
if err != nil {
return nil, err
}
for _, az := range azs.AvailabilityZones {
if *az.State == "available" {
if *az.State == ec2.AvailabilityZoneStateAvailable {
zones = append(zones, *az.ZoneName)
}
}
Expand Down Expand Up @@ -377,8 +377,7 @@ func (e *Ec2Infoer) getSpotPricesFromPrometheus(region string) (map[string]produ

func (e *Ec2Infoer) getCurrentSpotPrices(region string) (map[string]productinfo.SpotPriceInfo, error) {
priceInfo := make(map[string]productinfo.SpotPriceInfo)
ec2Svc := ec2.New(e.session, &aws.Config{Region: aws.String(region)})
err := ec2Svc.DescribeSpotPriceHistoryPages(&ec2.DescribeSpotPriceHistoryInput{
err := e.ec2Describer(region).DescribeSpotPriceHistoryPages(&ec2.DescribeSpotPriceHistoryInput{
StartTime: aws.Time(time.Now()),
ProductDescriptions: []*string{aws.String("Linux/UNIX")},
}, func(history *ec2.DescribeSpotPriceHistoryOutput, lastPage bool) bool {
Expand Down
Loading

0 comments on commit 23acd4b

Please sign in to comment.