Skip to content

Commit 70be469

Browse files
committed
major docs
1 parent f13c292 commit 70be469

File tree

5 files changed

+51
-15
lines changed

5 files changed

+51
-15
lines changed

cmd/analyze.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ var (
1818
details bool
1919
)
2020

21+
// todo these should change to tetrate-hosted s3 files, with which we can send over cluster information
22+
// to track usage patterns.
2123
const (
2224
gcpPricingLocation = "https://raw.githubusercontent.com/tetratelabs/istio-cost-analyzer/master/pricing/gcp/gcp_pricing.json"
2325
awsPricingLocation = "https://raw.githubusercontent.com/tetratelabs/istio-cost-analyzer/master/pricing/aws/aws_pricing.json"
@@ -28,8 +30,8 @@ var analyzeCmd = &cobra.Command{
2830
Short: "List all the pod to pod links in the mesh",
2931
Long: ``,
3032
RunE: func(cmd *cobra.Command, args []string) error {
31-
dapani, err := pkg.NewDapaniProm(prometheusEndpoint)
32-
kubeClient := pkg.NewDapaniKubeClient()
33+
analyzerProm, err := pkg.NewAnalyzerProm(prometheusEndpoint)
34+
kubeClient := pkg.NewAnalyzerKube()
3335
if err != nil {
3436
return err
3537
}
@@ -43,26 +45,32 @@ var analyzeCmd = &cobra.Command{
4345
return errors.New("provide different cloud")
4446
}
4547
}
48+
// initialize analyzer
4649
cost, err := pkg.NewCostAnalysis(pricePath)
4750
if err != nil {
4851
return err
4952
}
50-
go dapani.PortForwardProm()
51-
if err := dapani.WaitForProm(); err != nil {
53+
// port-forward prometheus asynchronously and wait for it to be ready
54+
go analyzerProm.PortForwardProm()
55+
if err := analyzerProm.WaitForProm(); err != nil {
5256
return err
5357
}
5458
duration, err := time.ParseDuration(queryBefore)
5559
if err != nil {
5660
return err
5761
}
58-
podCalls, err := dapani.GetPodCalls(duration)
62+
// query prometheus for raw pod calls
63+
podCalls, err := analyzerProm.GetPodCalls(duration)
5964
if err != nil {
6065
return err
6166
}
67+
// transform raw pod calls to locality information
6268
localityCalls, err := kubeClient.GetLocalityCalls(podCalls, cloud)
6369
if err != nil {
6470
return err
6571
}
72+
//localityCalls[0].From = "us-west1-c"
73+
// calculate egress given locality information
6674
totalCost, err := cost.CalculateEgress(localityCalls)
6775
if err != nil {
6876
return err

pkg/call.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ func PrintCostTable(calls []*Call, total float64, details bool) {
4949
}
5050

5151
func printMinifiedCostTable(calls []*Call) {
52-
// collapse into set by source
5352
// todo should we group by source & locality or just source
5453
// foo in us-west1-b might be treated diff from foo in us-west1-a
5554
// right now we group by just source, so all localities are grouped in the same row
@@ -108,6 +107,7 @@ func kubernetesify(table *tablewriter.Table) {
108107
table.SetBorder(false)
109108
}
110109

110+
// PodCall represents raw pod data, not containing locality or cost information.
111111
type PodCall struct {
112112
FromPod string
113113
FromWorkload string

pkg/kube.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,19 @@ import (
1111
"path/filepath"
1212
)
1313

14+
// KubeClient just wraps the kubernetes API.
15+
// todo should we just do:
16+
// ```
17+
// type KubeClient kubernetes.ClientSet
18+
// ```
19+
// if we get no value from just wrapping?
1420
type KubeClient struct {
1521
clientSet *kubernetes.Clientset
1622
}
1723

18-
func NewDapaniKubeClient() *KubeClient {
24+
// NewAnalyzerKube creates a clientset using the kubeconfig found in the home directory.
25+
// todo make kubeconfig a settable parameter in analyzer.go
26+
func NewAnalyzerKube() *KubeClient {
1927
var kubeconfig *string
2028
if home := homedir.HomeDir(); home != "" {
2129
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
@@ -40,10 +48,13 @@ func NewDapaniKubeClient() *KubeClient {
4048
}
4149
}
4250

51+
// GetLocalityCalls uses an array of PodCall to associate localities with these pods, getting this data
52+
// from the kubernetes API. We can get localities by going from pod -> node -> topology.
4353
func (k *KubeClient) GetLocalityCalls(podCalls []*PodCall, cloud string) ([]*Call, error) {
4454
calls := make([]*Call, 0)
45-
// key is just source/destination service/locality. No call size info
46-
// value is full Call
55+
// serviceCallMap's keys are just workload/locality links, without any call size information,
56+
// while the value is the full, aggregated call value for that link. We do this because there may
57+
// exist multiple pods that cause the same workload/locality link, and we don't want them to duplicate.
4758
serviceCallMap := make(map[Call]*Call)
4859
for i := 0; i < len(podCalls); i++ {
4960
fromNode, err := k.getPodNode(podCalls[i].FromPod)
@@ -68,6 +79,7 @@ func (k *KubeClient) GetLocalityCalls(podCalls []*PodCall, cloud string) ([]*Cal
6879
ToWorkload: podCalls[i].ToWorkload,
6980
To: toLocality,
7081
}
82+
// either create a new entry, or add to an existing one.
7183
if _, ok := serviceCallMap[serviceLocalityKey]; !ok {
7284
serviceCallMap[serviceLocalityKey] = &serviceLocalityKey
7385
serviceLocalityKey.CallSize = podCalls[i].CallSize
@@ -81,6 +93,7 @@ func (k *KubeClient) GetLocalityCalls(podCalls []*PodCall, cloud string) ([]*Cal
8193
return calls, nil
8294
}
8395

96+
// getPodNode gets the node associated with a given pod name in the default namespece.
8497
func (k *KubeClient) getPodNode(name string) (string, error) {
8598
pod, err := k.clientSet.CoreV1().Pods("default").Get(context.TODO(), name, metav1.GetOptions{})
8699
if err != nil {
@@ -90,6 +103,7 @@ func (k *KubeClient) getPodNode(name string) (string, error) {
90103
return pod.Spec.NodeName, nil
91104
}
92105

106+
// getNodeLocality gets the locality given by topology.kubernetes.io.
93107
func (k *KubeClient) getNodeLocality(name, cloud string) (string, error) {
94108
// if we are on AWS, we want to just get region, because availability zones
95109
// are not supported yet.

pkg/prom.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,35 @@ import (
1111
"time"
1212
)
1313

14-
type DapaniProm struct {
14+
// CostAnalyzerProm holds the prometheus routines necessary to collect
15+
// service<->service traffic data.
16+
type CostAnalyzerProm struct {
1517
promEndpoint string
1618
errChan chan error
1719
client api.Client
1820
}
1921

20-
func NewDapaniProm(promEndpoint string) (*DapaniProm, error) {
22+
// NewAnalyzerProm creates a prometheus client given the endpoint,
23+
// and errors out if the endpoint is invalid.
24+
func NewAnalyzerProm(promEndpoint string) (*CostAnalyzerProm, error) {
2125
client, err := api.NewClient(api.Config{
2226
Address: promEndpoint,
2327
})
2428
if err != nil {
2529
fmt.Printf("cannot initialize prom lib: %v", err)
2630
return nil, err
2731
}
28-
return &DapaniProm{
32+
return &CostAnalyzerProm{
2933
promEndpoint: promEndpoint,
3034
errChan: make(chan error),
3135
client: client,
3236
}, nil
3337
}
3438

35-
func (d *DapaniProm) PortForwardProm() {
39+
// PortForwardProm will execute a kubectl port-forward command, forwarding the inbuild prometheus
40+
// deployment to port 9090 on localhost. This is executed asynchronously, and if there is an error,
41+
// it is sent into d.errChan.
42+
func (d *CostAnalyzerProm) PortForwardProm() {
3643
cmd := exec.Command("kubectl", "-n", "istio-system", "port-forward", "deployment/prometheus", "9990:9090")
3744
o, err := cmd.CombinedOutput()
3845
if err != nil {
@@ -42,7 +49,9 @@ func (d *DapaniProm) PortForwardProm() {
4249
}
4350
}
4451

45-
func (d *DapaniProm) WaitForProm() error {
52+
// WaitForProm just pings the prometheus endpoint until it gets a code within [200, 300).
53+
// It selects for that event and an error coming in from d.errChan.
54+
func (d *CostAnalyzerProm) WaitForProm() error {
4655
ticker := time.NewTicker(500 * time.Millisecond)
4756
fmt.Println("Waiting for prometheus to be ready...")
4857
for {
@@ -59,7 +68,10 @@ func (d *DapaniProm) WaitForProm() error {
5968
}
6069
}
6170
}
62-
func (d *DapaniProm) GetPodCalls(since time.Duration) ([]*PodCall, error) {
71+
72+
// GetPodCalls queries the prometheus API for istio_request_bytes_sum, given a time range.
73+
// todo take an actual timerange, and not the hacky "since" parameter.
74+
func (d *CostAnalyzerProm) GetPodCalls(since time.Duration) ([]*PodCall, error) {
6375
promApi := v1.NewAPI(d.client)
6476
calls := make([]*PodCall, 0)
6577
query := "istio_request_bytes_sum{destination_pod!=\"\", destination_pod!=\"unknown\"}"

pricing/aws/pull_aws_rate_prices.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ This doesn't work for all the regions (for some reason), but it works
2121
for the major ones, which is good enough for now (?)
2222
2323
Don't use this in prod (please).
24+
25+
Not even going to bother documenting.
2426
*/
2527

2628
var out string

0 commit comments

Comments
 (0)