Skip to content

Commit 7ec888a

Browse files
author
sajit
committed
compiling
Signed-off-by: Sajit Kunnumkal <[email protected]>
1 parent 1cbc4f9 commit 7ec888a

File tree

4 files changed

+215
-51
lines changed

4 files changed

+215
-51
lines changed

pkg/plugins/snowflake/cmd/main/main.go

Lines changed: 91 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,30 @@ package main
33
import (
44
"database/sql"
55
"fmt"
6+
"time"
67

8+
"github.com/hashicorp/go-plugin"
79
commonconfig "github.com/opencost/opencost-plugins/common/config"
810
commonrequest "github.com/opencost/opencost-plugins/common/request"
911
snowflakeconfig "github.com/opencost/opencost-plugins/pkg/plugins/snowflake/config"
1012
snowflakeplugin "github.com/opencost/opencost-plugins/pkg/plugins/snowflake/plugin"
1113
"github.com/opencost/opencost/core/pkg/log"
1214
"github.com/opencost/opencost/core/pkg/model/pb"
1315
"github.com/opencost/opencost/core/pkg/opencost"
16+
ocplugin "github.com/opencost/opencost/core/pkg/plugin"
17+
"google.golang.org/protobuf/types/known/timestamppb"
1418
)
1519

20+
// handshakeConfigs are used to just do a basic handshake between
21+
// a plugin and host. If the handshake fails, a user friendly error is shown.
22+
// This prevents users from executing bad plugins or executing a plugin
23+
// directory. It is a UX feature, not a security feature.
24+
var handshakeConfig = plugin.HandshakeConfig{
25+
ProtocolVersion: 1,
26+
MagicCookieKey: "PLUGIN_NAME",
27+
MagicCookieValue: "snowflake",
28+
}
29+
1630
// SnowflakeClient defines the interface for interacting with Snowflake
1731
type SnowflakeClient interface {
1832
ExecuteQuery(query string) (*sql.Rows, error)
@@ -24,6 +38,17 @@ type snowflakeClient struct {
2438
}
2539

2640
// NewSnowflakeClient creates and returns a new SnowflakeClient instance
41+
// NewSnowflakeClient creates a new Snowflake client using the provided Snowflake configuration.
42+
// It constructs a DSN (Data Source Name) string from the configuration and attempts to open a connection to Snowflake.
43+
// If the connection is successful and the database is reachable, it returns a SnowflakeClient instance.
44+
// If there is an error during the connection or ping process, it returns an error.
45+
//
46+
// Parameters:
47+
// - snowflakeConfig: A pointer to a SnowflakeConfig struct containing the necessary configuration details.
48+
//
49+
// Returns:
50+
// - SnowflakeClient: An instance of the SnowflakeClient interface if the connection is successful.
51+
// - error: An error if there is an issue with the connection or ping process.
2752
func NewSnowflakeClient(snowflakeConfig *snowflakeconfig.SnowflakeConfig) (SnowflakeClient, error) {
2853
dsn := fmt.Sprintf("user=%s password=%s account=%s db=%s schema=%s warehouse=%s",
2954
snowflakeConfig.Username,
@@ -58,32 +83,48 @@ type SnowflakeCostSource struct {
5883

5984
// GetInvoices fetches invoices from Snowflake
6085
func GetInvoices(snowflakeClient SnowflakeClient) ([]snowflakeplugin.LineItem, error) {
61-
// Example query
62-
//TODO make sure that query maps to snowflakeplugin.LineItem
63-
query := `
64-
SELECT
65-
date_trunc('day', start_time) AS usage_date,
66-
SUM(credits_used) AS total_credits
67-
FROM snowflake.account_usage.warehouse_metering_history
68-
WHERE start_time >= DATEADD(day, -30, CURRENT_TIMESTAMP())
69-
GROUP BY usage_date
70-
ORDER BY usage_date DESC
71-
`
86+
87+
query := snowflakeplugin.CreditsByWarehouse()
7288

7389
// Execute the query using the Snowflake client
7490
rows, err := snowflakeClient.ExecuteQuery(query)
7591
if err != nil {
76-
log.Fatal("Query execution failed:", err)
92+
93+
log.Fatalf("Query execution failed:", err)
7794
return nil, err
7895
}
7996
defer rows.Close()
80-
// Implement the logic to fetch pending invoices from Snowflake
81-
// This is a placeholder implementation
82-
return rows, nil
97+
98+
var lineItems []snowflakeplugin.LineItem
99+
100+
for rows.Next() {
101+
var warehouse string
102+
var credits float32
103+
var date string
104+
105+
if err := rows.Scan(&date, &warehouse, &credits); err != nil {
106+
log.Fatalf("", err)
107+
}
108+
109+
lineItem := snowflakeplugin.LineItem{
110+
WarehouseName: warehouse,
111+
CreditUsed: credits,
112+
Date: date,
113+
}
114+
115+
lineItems = append(lineItems, lineItem)
116+
}
117+
118+
if err = rows.Err(); err != nil {
119+
log.Fatalf("", err)
120+
}
121+
122+
return lineItems, nil
123+
83124
}
84125

85126
func main() {
86-
127+
87128
log.Debug("Initializing Snowflake plugin")
88129

89130
configFile, err := commonconfig.GetConfigFilePath()
@@ -102,12 +143,12 @@ func main() {
102143
}
103144

104145
client, err := NewSnowflakeClient(snowflakeConfig)
105-
146+
106147
if err != nil {
107-
log.Fatal("Failed to create Snowflake client:", err)
148+
log.Fatalf("Failed to create Snowflake client:", err)
108149
}
109150
snowflakeCostSource := SnowflakeCostSource{
110-
snowflakeClient: client
151+
snowflakeClient: client,
111152
}
112153
defer client.(*snowflakeClient).db.Close()
113154

@@ -122,11 +163,9 @@ func main() {
122163
GRPCServer: plugin.DefaultGRPCServer,
123164
})
124165

125-
126-
127-
128166
}
129167
func (s *SnowflakeCostSource) GetCustomCosts(req *pb.CustomCostRequest) []*pb.CustomCostResponse {
168+
130169
results := []*pb.CustomCostResponse{}
131170

132171
requestErrors := commonrequest.ValidateRequest(req)
@@ -164,31 +203,42 @@ func (s *SnowflakeCostSource) GetCustomCosts(req *pb.CustomCostRequest) []*pb.Cu
164203
}
165204

166205
log.Debugf("fetching atlas costs for window %v", target)
167-
168-
// Print the results
169-
fmt.Println("Date\t\tTotal Credits")
170-
for rows.Next() {
171-
var date string
172-
var credits float64
173-
var warehouse string
174-
if err := rows.Scan(&date, &credits, &warehouse); err != nil {
175-
log.Fatal(err)
176-
}
177-
//TODO extract lineItem into CustomCostResponse
178-
//result := a.getAtlasCostsForWindow(&target, lineItems)
206+
result := s.GetSnowflakeCostsForWindow(&target, lineItems)
179207

180208
results = append(results, result)
181-
//fmt.Printf("%s\t%.2f\n", date, credits)
182209

183210
}
184211

185-
// Check for errors from iterating over rows
186-
if err = rows.Err(); err != nil {
187-
log.Fatal(err)
188-
}
212+
return results
189213

214+
}
215+
func filterLineItemsByWindow(win *opencost.Window, lineItems []snowflakeplugin.LineItem) []*pb.CustomCost {
216+
var filteredItems []*pb.CustomCost
217+
for _, li := range lineItems {
218+
if li.Date == win.Start().Format("2006-01-02 15:04:05") {
219+
cost := &pb.CustomCost{
220+
UsageQuantity: li.CreditUsed,
221+
ResourceName: li.WarehouseName,
222+
}
223+
filteredItems = append(filteredItems, cost)
224+
}
190225
}
226+
return filteredItems
227+
}
191228

192-
return results
193-
229+
func (s *SnowflakeCostSource) GetSnowflakeCostsForWindow(win *opencost.Window, lineItems []snowflakeplugin.LineItem) *pb.CustomCostResponse {
230+
231+
costsInWindow := filterLineItemsByWindow(win, lineItems)
232+
resp := pb.CustomCostResponse{
233+
Metadata: map[string]string{"api_client_version": "v1"},
234+
CostSource: "data_storage",
235+
Domain: "snowflake",
236+
Version: "v1",
237+
Currency: "USD",
238+
Start: timestamppb.New(*win.Start()),
239+
End: timestamppb.New(*win.End()),
240+
Errors: []string{},
241+
Costs: costsInWindow,
242+
}
243+
return &resp
194244
}

pkg/plugins/snowflake/go.mod

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,41 @@
11
module github.com/opencost/opencost-plugins/pkg/plugins/snowflake
22

3-
go 1.22.5
3+
go 1.22.7
44

55
replace github.com/opencost/opencost-plugins/common => ../../common
66

77
require (
8+
github.com/hashicorp/go-plugin v1.6.1
89
github.com/opencost/opencost-plugins/common v0.0.0-00010101000000-000000000000
9-
github.com/opencost/opencost/core v0.0.0-20240829194822-b82370afd830
10+
github.com/opencost/opencost/core v0.0.0-20250117200701-47c4b6817505
11+
google.golang.org/protobuf v1.33.0
1012

1113
)
1214

1315
require (
16+
github.com/fatih/color v1.16.0 // indirect
1417
github.com/fsnotify/fsnotify v1.6.0 // indirect
18+
github.com/go-logr/logr v1.2.4 // indirect
19+
github.com/goccy/go-json v0.9.11 // indirect
20+
github.com/gogo/protobuf v1.3.2 // indirect
1521
github.com/golang/protobuf v1.5.3 // indirect
22+
github.com/google/gofuzz v1.2.0 // indirect
23+
github.com/hashicorp/errwrap v1.0.0 // indirect
24+
github.com/hashicorp/go-hclog v1.6.2 // indirect
25+
github.com/hashicorp/go-multierror v1.1.1 // indirect
1626
github.com/hashicorp/hcl v1.0.0 // indirect
27+
github.com/hashicorp/yamux v0.1.1 // indirect
28+
github.com/json-iterator/go v1.1.12 // indirect
1729
github.com/kr/pretty v0.3.1 // indirect
1830
github.com/magiconair/properties v1.8.5 // indirect
31+
github.com/mattn/go-colorable v0.1.13 // indirect
32+
github.com/mattn/go-isatty v0.0.20 // indirect
33+
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
1934
github.com/mitchellh/mapstructure v1.5.0 // indirect
35+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
36+
github.com/modern-go/reflect2 v1.0.2 // indirect
37+
github.com/oklog/run v1.1.0 // indirect
38+
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
2039
github.com/pelletier/go-toml v1.9.3 // indirect
2140
github.com/rs/zerolog v1.26.1 // indirect
2241
github.com/spf13/afero v1.6.0 // indirect
@@ -26,13 +45,20 @@ require (
2645
github.com/spf13/viper v1.8.1 // indirect
2746
github.com/stretchr/testify v1.9.0 // indirect
2847
github.com/subosito/gotenv v1.2.0 // indirect
29-
golang.org/x/net v0.21.0 // indirect
48+
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 // indirect
49+
golang.org/x/net v0.23.0 // indirect
3050
golang.org/x/sys v0.24.0 // indirect
3151
golang.org/x/text v0.17.0 // indirect
3252
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect
3353
google.golang.org/grpc v1.62.0 // indirect
34-
google.golang.org/protobuf v1.32.0 // indirect
3554
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
55+
gopkg.in/inf.v0 v0.9.1 // indirect
3656
gopkg.in/ini.v1 v1.67.0 // indirect
3757
gopkg.in/yaml.v2 v2.4.0 // indirect
58+
k8s.io/api v0.25.3 // indirect
59+
k8s.io/apimachinery v0.25.3 // indirect
60+
k8s.io/klog/v2 v2.80.0 // indirect
61+
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
62+
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
63+
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
3864
)

0 commit comments

Comments
 (0)