Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Atlas plugin #23

Closed
wants to merge 28 commits into from
Closed

Atlas plugin #23

wants to merge 28 commits into from

Conversation

sajit
Copy link
Contributor

@sajit sajit commented Aug 21, 2024

What does this PR change?

  • Introduces method to create cost explorer query

Does this PR relate to any other PRs?

  • No

How will this PR impact users?

  • Not sure

Does this PR address any GitHub or Zendesk issues?

  • No

How was this PR tested?

  • Unit tets

Does this PR require changes to documentation?

mongodb-atlas/cmd/main.go Outdated Show resolved Hide resolved
@ameijer
Copy link
Contributor

ameijer commented Aug 22, 2024

Amazing, Sajit! I created an issue for tracking here: #24

@ameijer ameijer linked an issue Aug 22, 2024 that may be closed by this pull request
Copy link
Contributor

@ameijer ameijer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regarding project structure - I think you are actually pretty close. The main package is conventionally where the main() method is... you will always have a main method, each plugin is its own standalone go program.

I regret naming the plugin implementation package datadogplugin, i would change the mongodbatlasplugin package to just be named plugin... less typing to use that stuff, haha.

I'd also set up a test package that can hold an integration testing harness for this

mongodb-atlas/go.mod Outdated Show resolved Hide resolved
mongodb-atlas/cmd/main.go Outdated Show resolved Hide resolved
// TODO move these types to mongodbatlasplugin package
type CreateCostExplorerQueryPayload struct {
Clusters []string `json:"clusters"`
EndDate string `json:"endDate"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you considered more strongly typing this with a time.Time object? GO's json serializer is very good and I bet the API would be happy with what it gets serialized to

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ive modified the function itself to take time.Time. So its more strict. Internally we are creating this struct. when I tried changing EndDate to time.Time issue I was running into was that the string was of the format yyyy-mm-dd+timestamp and mongo atlas didn't like it. Instead of figuring out how to modify the json.Marshal to marshal a time type to yyyy-mm-dd without the timestamp I just do a parse in the function itself.

mongodb-atlas/cmd/main.go Outdated Show resolved Hide resolved
mongodb-atlas/cmd/main.go Outdated Show resolved Hide resolved
mongodb-atlas/cmd/main_test.go Outdated Show resolved Hide resolved
fmt.Println(error)
}

func getTruth() bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

likewise to lowercase variables in structs, this function is encapsulated in the main package


payloadJson, marshallingError := json.Marshal(payload)
if marshallingError != nil {
return "error", marshallingError
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

golang error handling is one of the most interesting and different parts of the language. Even after 5 years of it being my daily driver, I can't decide if I like it better or not than Java.

Basically, go never throws exceptions. if you do a nil access, it will panic with a segfault like C, but you can't use exception handling to deal with unexpected errors. you will see error handles like this sprinkled throughout all go code.

We have found the following approach works:

  1. when returning an error, your "good" value should be nil if a pointer, or an empty value if not a pointer.
  2. log the error in context (import the logging package from opencost, that will handle logger setup for you, I can point you to examples)
  3. wrap the error before you return it. As the error gets passed up the stack, you have nested wrapped messages which function similar to the stacktrace in a java exception.

Here's how I would handle this error in this case:

if marshallingError != nil {
   msg := fmt.Sprintf("createCostExplorerQueryToken: error marshaling JSON payload: %v", err)
   log.Error(msg)
   return "", fmt.Errorf(msg)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will take point on this.

}
defer response.Body.Close()

fmt.Println("response Status:", response.Status)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd go ahead and move all this to a debug or trace level logger. This will be useful for ongoing maintenance

package mongodbatlas

type MongoDBAtlasConfig struct {
PublicKey string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd go ahead and get this reading off the file system during the boot sequence. Check out how we do it in getDatadogConfig and getConfigFilePath() in that plugin. This config will grow quickly as this matures and you will be glad to get it in a file ASAP before you get trapped in env var hell world

@kwombach12
Copy link

@sajit Thanks so much for your contribution! We are super excited to work with you on this. Please don't hesitate to reach out if you have any issues or questions.

@sajit sajit marked this pull request as draft August 27, 2024 20:55
@sajit sajit force-pushed the atlas-plugin branch 3 times, most recently from 3683257 to 1225ea2 Compare August 27, 2024 21:30
@sajit sajit marked this pull request as ready for review August 28, 2024 21:19
@sajit
Copy link
Contributor Author

sajit commented Aug 28, 2024

@ameijer @kwombach12 Thanks for the feedback. Kindly take another look. Ive addressed most of the comments / deleted unused code. A few things to note. In main_test.go, all but 1 test are unit tests.
For, TestMain test in mongodb-atlas/cmd/main_test.go to run the execution environment , needs to have some env variables set . (its documented in the comments) . This is a true integration test - ie it will make a real call to MongoDB atlas.

@sajit
Copy link
Contributor Author

sajit commented Aug 28, 2024

Also could I get some help understanding whats happening with DCO - I believe I have used the correct commit message template. thanks in advance

}

// pass list of orgs , start date, end date
func createCostExplorerQueryToken(org string, startDate time.Time, endDate time.Time,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed startDate, endDate to be time.Time

@ameijer
Copy link
Contributor

ameijer commented Aug 29, 2024

wow the DCO thing is weird. Have you set up GPG keys? is it related to that?

If all else fails, you can always just copy the files into a new branch

@sajit
Copy link
Contributor Author

sajit commented Aug 29, 2024

@ameijer pretty silly apparently its because DCO requires your first name and last name and my github was just my first name. lol. Anyways I think its passing DCO check now. Should be good to be reviewed.

Copy link
Contributor

@ameijer ameijer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exciting stuff!

Service string `json:"service"`
UsageAmount float32 `json:"usageAmount"`
UsageDate string `json:"usageDate"`
//"invoiceId":"66d7254246a21a41036ff315","organizationId":"66d7254246a21a41036ff2e9","organizationName":"Kubecost","service":"Clusters","usageAmount":51.19,"usageDate":"2024-09-01"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you redact the IDs here?

@@ -0,0 +1,29 @@
package plugin

type CreateCostExplorerQueryPayload struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nice

// if config.LogLevel != "debug" {
// t.Errorf("expected log level to be 'debug', but got: %s", config.LogLevel)
// }
// })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why commented?

.gitmessage.txt Outdated
@@ -0,0 +1,2 @@
#Commit Message template
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you remove these files?

// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gitignored this and removed it in sajit#4

for _, invoice := range costResponse.UsageDetails {
// Create a new pb.CustomCost for each Invoice
customCost := &pb.CustomCost{
Id: invoice.InvoiceId,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this ID is actually something you assign. You can just do UUID.NewUUIDV4String() from one of the many UUID packages out there.

func CreateCostExplorerQueryToken(org string, startDate time.Time, endDate time.Time,
client HTTPClient) (string, error) {
// Define the layout for the desired format
layout := "2006-01-02"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const


payload := atlasplugin.CreateCostExplorerQueryPayload{

EndDate: endDateString,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rm space above this

// Iterate over the UsageDetails in CostResponse
for _, invoice := range costResponse.UsageDetails {
// Create a new pb.CustomCost for each Invoice
customCost := &pb.CustomCost{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you set UsageUnit as USD on this too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on the metadata field, can you set an interpolated: true key/value?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another additional field that is super important is the ProviderID. We can sort of synthesize one. Maybe the providerID can be <orgid>/<invoiceid>/<service>

customCost := &pb.CustomCost{
Id: invoice.InvoiceId,
AccountName: invoice.OrganizationName,
ChargeCategory: invoice.Service,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would actually set ResourceName to the invoice.Service

sajit and others added 10 commits October 16, 2024 10:40
Init commit

cmd files

intermediate stop

Changing signature

adding scripts to gitignore

address review comments

address review comments

ignore mock test

failing test

Signed-off-by: sajit  <[email protected]>
fixed test

Make test optional
Signed-off-by: sajit  <[email protected]>

adding tests
Signed-off-by: sajit <[email protected]>

Added tests
Signed-off-by: sajit  <[email protected]>

Delete unused struct
Signed-off-by: sajit  <[email protected]>
Signed-off-by: sajit <[email protected]>
Merge Alex's PR to continue work on branch

Signed-off-by: sajit <[email protected]>
Signed-off-by: sajit <[email protected]>
Signed-off-by: sajit <[email protected]>
Signed-off-by: sajit <[email protected]>
Signed-off-by: sajit <[email protected]>
sajit and others added 18 commits October 16, 2024 10:40
Signed-off-by: sajit <[email protected]>
Signed-off-by: sajit <[email protected]>
Signed-off-by: Alex Meijer <[email protected]>
Signed-off-by: sajit <[email protected]>
prep for testing, fix build

Signed-off-by: Alex Meijer <[email protected]>
Signed-off-by: Alex Meijer <[email protected]>
Signed-off-by: sajit <[email protected]>
Signed-off-by: sajit <[email protected]>
Signed-off-by: sajit <[email protected]>
* OpenAI Plugin MVP

Signed-off-by: Alex Meijer <[email protected]>

* code review fixes

Signed-off-by: Alex Meijer <[email protected]>

* add MAINTAINERS

Signed-off-by: Alex Meijer <[email protected]>

* only attempt to read if no error

Signed-off-by: Alex Meijer <[email protected]>

---------

Signed-off-by: Alex Meijer <[email protected]>
Signed-off-by: sajit <[email protected]>
Signed-off-by: sajit <[email protected]>
* implement validator, small bugfix

Signed-off-by: Alex Meijer <[email protected]>

* additional testing

Signed-off-by: Alex Meijer <[email protected]>

---------

Signed-off-by: Alex Meijer <[email protected]>
Signed-off-by: sajit <[email protected]>
Signed-off-by: sajit <[email protected]>
@ameijer
Copy link
Contributor

ameijer commented Oct 16, 2024

obsoleted by #41

@ameijer ameijer closed this Oct 16, 2024
@sajit sajit deleted the atlas-plugin branch October 19, 2024 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

OpenCost Plugin For MongoDB Atlas
3 participants