Skip to content

Commit dc8071f

Browse files
Merge pull request #70 from ksctl/feature/co2
Feature/co2
1 parent 2c23413 commit dc8071f

File tree

7 files changed

+261
-491
lines changed

7 files changed

+261
-491
lines changed

cmd/cli.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type KsctlCommand struct {
4040
menuDriven cli.MenuDriven
4141
KsctlConfig *config.Config
4242
telemetry *telemetry.Telemetry
43-
inMemInstanceTypesInReg map[string]provider.InstanceRegionOutput
43+
inMemInstanceTypesInReg provider.InstancesRegionOutput
4444
}
4545

4646
func New() (*KsctlCommand, error) {

cmd/create.go

Lines changed: 180 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ package cmd
1717
import (
1818
"fmt"
1919
"os"
20-
"slices"
2120
"time"
2221

22+
"github.com/ksctl/ksctl/v2/pkg/provider/optimizer"
23+
2324
"github.com/fatih/color"
2425
"github.com/ksctl/ksctl/v2/pkg/consts"
2526
"github.com/ksctl/ksctl/v2/pkg/provider"
@@ -62,9 +63,57 @@ ksctl create --help
6263
return cmd
6364
}
6465

65-
func (k *KsctlCommand) metadataForSelfManagedCluster(
66-
meta *controller.Metadata,
67-
) {
66+
type CliRecommendation struct {
67+
isOptimizeInstanceRegionReady *optimizer.RecommendationAcrossRegions
68+
errInRecommendation error
69+
}
70+
71+
func (k *KsctlCommand) CostOptimizeAcrossRegion(inp chan CliRecommendation, meta *controller.Metadata) {
72+
ticker := time.NewTicker(2 * time.Second)
73+
defer ticker.Stop()
74+
for {
75+
select {
76+
case o := <-inp:
77+
optimizeResp, errResp := o.isOptimizeInstanceRegionReady, o.errInRecommendation
78+
if errResp != nil {
79+
k.l.Warn(k.Ctx, "Failed to get the recommendation", "Reason", errResp)
80+
return
81+
}
82+
83+
if len(optimizeResp.RegionRecommendations) == 0 {
84+
k.l.Success(k.Ctx, "✨ No recommendation available for the selected region")
85+
return
86+
}
87+
88+
k.PrintRecommendation(meta.ClusterType, optimizeResp)
89+
90+
availRegions := []string{"Don't change"}
91+
for _, _o := range optimizeResp.RegionRecommendations {
92+
availRegions = append(availRegions, _o.Region)
93+
}
94+
95+
v, err := k.menuDriven.DropDownList(fmt.Sprintf("Region Switch. Currently set (%s)", meta.Region), availRegions,
96+
cli.WithDefaultValue("Don't change"),
97+
)
98+
if err != nil {
99+
k.l.Error("Skipping it becuase failed to get the region switch", "Reason", err)
100+
return
101+
}
102+
if v == "Don't change" {
103+
return
104+
}
105+
106+
k.l.Print(k.Ctx, "changed the region", "from", color.HiRedString(meta.Region), "to", color.HiGreenString(v))
107+
meta.Region = v
108+
109+
return
110+
case <-ticker.C:
111+
k.l.Print(k.Ctx, "Still optimizing instance types...")
112+
}
113+
}
114+
}
115+
116+
func (k *KsctlCommand) metadataForSelfManagedCluster(meta *controller.Metadata) {
68117
metaClient, err := controllerMeta.NewController(
69118
k.Ctx,
70119
k.l,
@@ -122,10 +171,29 @@ func (k *KsctlCommand) metadataForSelfManagedCluster(
122171
meta.NoDS = v
123172
}
124173

125-
isOptimizeInstanceRegionReady := make(chan []RecommendationSelfManagedCost)
174+
var (
175+
isOptimizeInstanceRegionReady chan CliRecommendation
176+
)
177+
isOptimizeInstanceRegionReady = make(chan CliRecommendation)
126178

127179
go func() {
128-
isOptimizeInstanceRegionReady <- k.OptimizeSelfManagedInstanceTypesAcrossRegions(meta, allAvailRegions, cp, wp, etcd, lb)
180+
res, err := metaClient.CostOptimizeAcrossRegions(
181+
allAvailRegions, meta.Region,
182+
controllerMeta.CostOptimizerInput{
183+
ControlPlane: cp,
184+
WorkerPlane: wp,
185+
DataStorePlane: etcd,
186+
LoadBalancer: lb,
187+
CountOfControlPlaneNodes: meta.NoCP,
188+
CountOfWorkerNodes: meta.NoWP,
189+
CountOfEtcdNodes: meta.NoDS,
190+
},
191+
)
192+
193+
isOptimizeInstanceRegionReady <- CliRecommendation{
194+
isOptimizeInstanceRegionReady: res,
195+
errInRecommendation: err,
196+
}
129197
}()
130198

131199
bootstrapVers, err := metaClient.ListAllBootstrapVersions()
@@ -172,52 +240,7 @@ func (k *KsctlCommand) metadataForSelfManagedCluster(
172240
os.Exit(1)
173241
}
174242

175-
func() {
176-
ticker := time.NewTicker(2 * time.Second)
177-
defer ticker.Stop()
178-
for {
179-
select {
180-
case o := <-isOptimizeInstanceRegionReady:
181-
k.PrintRecommendationSelfManagedCost(
182-
o,
183-
meta.NoCP,
184-
meta.NoWP,
185-
meta.NoDS,
186-
cp.Sku,
187-
wp.Sku,
188-
etcd.Sku,
189-
lb.Sku,
190-
)
191-
pos := slices.IndexFunc(o, func(i RecommendationSelfManagedCost) bool {
192-
return i.region == meta.Region
193-
})
194-
o = append(o[:pos], o[pos+1:]...)
195-
196-
availRegions := []string{"Don't change"}
197-
for _, _o := range o[:5] {
198-
availRegions = append(availRegions, _o.region)
199-
}
200-
201-
v, err := k.menuDriven.DropDownList(fmt.Sprintf("Region Switch. Currently set (%s)", meta.Region), availRegions,
202-
cli.WithDefaultValue("Don't change"),
203-
)
204-
if err != nil {
205-
k.l.Error("Skipping it becuase failed to get the region switch", "Reason", err)
206-
return
207-
}
208-
if v == "Don't change" {
209-
return
210-
}
211-
212-
k.l.Print(k.Ctx, "changed the region", "from", color.HiRedString(meta.Region), "to", color.HiGreenString(v))
213-
meta.Region = v
214-
215-
return
216-
case <-ticker.C:
217-
k.l.Print(k.Ctx, "Still optimizing instance types...")
218-
}
219-
}
220-
}()
243+
k.CostOptimizeAcrossRegion(isOptimizeInstanceRegionReady, meta)
221244

222245
managedCNI, defaultCNI, ksctlCNI, defaultKsctl, err := metaClient.ListBootstrapCNIs()
223246
if err != nil {
@@ -271,9 +294,7 @@ func (k *KsctlCommand) metadataForSelfManagedCluster(
271294
return
272295
}
273296

274-
func (k *KsctlCommand) metadataForManagedCluster(
275-
meta *controller.Metadata,
276-
) {
297+
func (k *KsctlCommand) metadataForManagedCluster(meta *controller.Metadata) {
277298
metaClient, err := controllerMeta.NewController(
278299
k.Ctx,
279300
k.l,
@@ -295,7 +316,9 @@ func (k *KsctlCommand) metadataForManagedCluster(
295316
meta.NoMP = v
296317
}
297318

298-
isOptimizeInstanceRegionReady := make(chan []RecommendationManagedCost)
319+
var (
320+
isOptimizeInstanceRegionReady chan CliRecommendation
321+
)
299322

300323
if meta.Provider != consts.CloudLocal {
301324
allAvailRegions := k.handleRegionSelection(metaClient, meta)
@@ -327,8 +350,21 @@ func (k *KsctlCommand) metadataForManagedCluster(
327350
offeringSelected = v
328351
}
329352

353+
isOptimizeInstanceRegionReady = make(chan CliRecommendation)
354+
330355
go func() {
331-
isOptimizeInstanceRegionReady <- k.OptimizeManagedOfferingsAcrossRegions(meta, allAvailRegions, listOfOfferings[offeringSelected], vm)
356+
res, err := metaClient.CostOptimizeAcrossRegions(
357+
allAvailRegions, meta.Region,
358+
controllerMeta.CostOptimizerInput{
359+
ManagedOffering: listOfOfferings[offeringSelected],
360+
ManagedPlane: vm,
361+
CountOfManagedNodes: meta.NoMP,
362+
},
363+
)
364+
isOptimizeInstanceRegionReady <- CliRecommendation{
365+
isOptimizeInstanceRegionReady: res,
366+
errInRecommendation: err,
367+
}
332368
}()
333369

334370
k.l.Print(k.Ctx, "Current Selection will cost you")
@@ -344,49 +380,7 @@ func (k *KsctlCommand) metadataForManagedCluster(
344380
os.Exit(1)
345381
}
346382

347-
func() {
348-
ticker := time.NewTicker(2 * time.Second)
349-
defer ticker.Stop()
350-
for {
351-
select {
352-
case o := <-isOptimizeInstanceRegionReady:
353-
k.PrintRecommendationManagedCost(
354-
o,
355-
meta.NoMP,
356-
listOfOfferings[offeringSelected].Sku,
357-
vm.Sku,
358-
)
359-
360-
pos := slices.IndexFunc(o, func(i RecommendationManagedCost) bool {
361-
return i.region == meta.Region
362-
})
363-
o = append(o[:pos], o[pos+1:]...)
364-
365-
availRegions := []string{"Don't change"}
366-
for _, _o := range o[:5] {
367-
availRegions = append(availRegions, _o.region)
368-
}
369-
370-
v, err := k.menuDriven.DropDownList(fmt.Sprintf("Region Switch. Currently set (%s)", meta.Region), availRegions,
371-
cli.WithDefaultValue("Don't change"),
372-
)
373-
if err != nil {
374-
k.l.Error("Skipping it becuase failed to get the region switch", "Reason", err)
375-
return
376-
}
377-
if v == "Don't change" {
378-
return
379-
}
380-
381-
k.l.Print(k.Ctx, "changed the region", "from", color.HiRedString(meta.Region), "to", color.HiGreenString(v))
382-
meta.Region = v
383-
384-
return
385-
case <-ticker.C:
386-
k.l.Print(k.Ctx, "Still optimizing instance types...")
387-
}
388-
}
389-
}()
383+
k.CostOptimizeAcrossRegion(isOptimizeInstanceRegionReady, meta)
390384
}
391385

392386
managedCNI, defaultCNI, ksctlCNI, defaultKsctl, err := metaClient.ListManagedCNIs()
@@ -452,3 +446,89 @@ func (k *KsctlCommand) metadataForManagedCluster(
452446

453447
return
454448
}
449+
450+
func (k *KsctlCommand) PrintRecommendation(
451+
clusterType consts.KsctlClusterType,
452+
optimizations *optimizer.RecommendationAcrossRegions) {
453+
454+
k.l.Print(k.Ctx,
455+
"Here is your recommendation",
456+
"Parameter", "Region wise cost",
457+
)
458+
459+
var headers []string
460+
var data [][]string
461+
462+
if clusterType == consts.ClusterTypeMang {
463+
headers = []string{
464+
"Region",
465+
"🏭 Direct Emission",
466+
fmt.Sprintf("ControlPlane (%s)", optimizations.ManagedOffering),
467+
fmt.Sprintf("WorkerPlane (%s)", optimizations.InstanceTypeWP),
468+
"Total Monthly Cost",
469+
}
470+
471+
for _, cost := range optimizations.RegionRecommendations {
472+
total := cost.TotalCost
473+
reg := cost.Region
474+
managed := cost.ControlPlaneCost
475+
worker := cost.WorkerPlaneCost
476+
477+
regEmissions := cost.Emissions
478+
var emissions string
479+
if regEmissions == nil {
480+
emissions = "N/A"
481+
} else {
482+
emissions = fmt.Sprintf("%.2f %s", regEmissions.DirectCarbonIntensity, regEmissions.Unit)
483+
}
484+
485+
data = append(data, []string{
486+
reg,
487+
emissions,
488+
fmt.Sprintf("$%.2f X 1", managed),
489+
fmt.Sprintf("$%.2f X %d", worker, optimizations.WorkerPlaneCount),
490+
fmt.Sprintf("$%.2f", total),
491+
})
492+
}
493+
494+
} else if clusterType == consts.ClusterTypeSelfMang {
495+
headers = []string{
496+
"Region",
497+
"🏭 Direct Emission",
498+
fmt.Sprintf("ControlPlane (%s)", optimizations.InstanceTypeCP),
499+
fmt.Sprintf("WorkerPlane (%s)", optimizations.InstanceTypeWP),
500+
fmt.Sprintf("DatastorePlane (%s)", optimizations.InstanceTypeDS),
501+
fmt.Sprintf("LoadBalancer (%s)", optimizations.InstanceTypeLB),
502+
"Total Monthly Cost",
503+
}
504+
505+
for _, cost := range optimizations.RegionRecommendations {
506+
total := cost.TotalCost
507+
reg := cost.Region
508+
cp := cost.ControlPlaneCost
509+
wp := cost.WorkerPlaneCost
510+
ds := cost.DataStoreCost
511+
lb := cost.LoadBalancerCost
512+
regEmissions := cost.Emissions
513+
514+
var emissions string
515+
if regEmissions == nil {
516+
emissions = "N/A"
517+
} else {
518+
emissions = fmt.Sprintf("%.2f %s", regEmissions.DirectCarbonIntensity, regEmissions.Unit)
519+
}
520+
521+
data = append(data, []string{
522+
reg,
523+
emissions,
524+
fmt.Sprintf("$%.2f X %d", cp, optimizations.ControlPlaneCount),
525+
fmt.Sprintf("$%.2f X %d", wp, optimizations.WorkerPlaneCount),
526+
fmt.Sprintf("$%.2f X %d", ds, optimizations.DataStoreCount),
527+
fmt.Sprintf("$%.2f X 1", lb),
528+
fmt.Sprintf("$%.2f", total),
529+
})
530+
}
531+
}
532+
533+
k.l.Table(k.Ctx, headers, data)
534+
}

0 commit comments

Comments
 (0)