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

feat: Config api 2 #9546

Closed
wants to merge 48 commits into from
Closed

feat: Config api 2 #9546

wants to merge 48 commits into from

Conversation

ssoroka
Copy link
Contributor

@ssoroka ssoroka commented Jul 27, 2021

replaces #8489

resolves #7519
resolves #7993
resolves #8016

internal/channel/fanout.go Outdated Show resolved Hide resolved
@ssoroka ssoroka mentioned this pull request Jul 27, 2021
_, _ = w.Write(bytes)
}

func (s *ConfigAPIService) runningPlugins(w http.ResponseWriter, req *http.Request) {
Copy link
Contributor

Choose a reason for hiding this comment

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

When there are no plugins this returns "null". I expected it to return an empty array. We should have a unit test for this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

resolved in 0ed2b60

Copy link
Contributor

Choose a reason for hiding this comment

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

Did you link the wrong commit? That one is about the linter. Looks like you meant efa4eec.

I manually retested to confirm that we get an empty array now. I see in controller_test.go near the end of TestInputPluginLifecycle there's a check for length 0 calling ListRunningPlugins, but len returns 0 on empty slice or nil.

We need unit tests that make http calls. The tests in controller_test.go are great but it's not enough just to test the methods of the api type.

Copy link
Member

Choose a reason for hiding this comment

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

There's unit tests with http calls in listener_test.go

plugins/configs/api/listener.go Show resolved Hide resolved
@reimda
Copy link
Contributor

reimda commented Aug 3, 2021

It looks like this branch introduces a problem handling os signals. If I start telegraf with a config.api but no inputs or outputs, then use the api to add an inputs.cpu and an outputs.file writing to stdout, the plugins are created fine but when I hit ^C, the program doesn't terminate.

On master, if I have a config file that only has an inputs.cpu and an outputs.file, I can hit ^C and it closes telegraf immediately.

plugins/configs/api/listener.go Show resolved Hide resolved
_, _ = w.Write(bytes)
}

func (s *ConfigAPIService) runningPlugins(w http.ResponseWriter, req *http.Request) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you link the wrong commit? That one is about the linter. Looks like you meant efa4eec.

I manually retested to confirm that we get an empty array now. I see in controller_test.go near the end of TestInputPluginLifecycle there's a check for length 0 calling ListRunningPlugins, but len returns 0 on empty slice or nil.

We need unit tests that make http calls. The tests in controller_test.go are great but it's not enough just to test the methods of the api type.

}

func (a *api) ListRunningPlugins() (runningPlugins []Plugin) {
if a == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

This func doesn't return whether a plugin is an input or an output. Since we have some plugins with the same name that are inputs and outputs (like inputs.file and outputs.file) we need to disambiguate them here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

plugin names should be inputs.file or outputs.file. There's a few places where this was missed and i'm currently cleaning them up.

require.EqualValues(t, 200, resp.StatusCode)
require.NoError(t, err)

resp, err = http.Get(srv.URL + "/plugins/running")
Copy link
Contributor

Choose a reason for hiding this comment

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

When deleting a plugin, does a response code of 200 guarantee that the request has been processed and the plugin deleted? In the test TestStartPlugin there is a for loop checking to make sure if the plugin has started running, wondering if that is necessary here or if the behavior is different.

Copy link
Contributor Author

@ssoroka ssoroka Aug 10, 2021

Choose a reason for hiding this comment

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

It does not guarantee the plugin has been removed as they're asynchronous. Will add something to wait appropriately.

Reason string
}{}

for statusResp.Status != "running" {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this for loop necessary because it could take sometime for a plugin to start running? We probably then want to return 202 to let the user know the request has been accepted and is still processing (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

202 Accepted doesn't seem quite right; the docs say it's "uncommital and may not be acted on", but that's not true as I've already initialized the plugin at this point and it has started, it just may not have gotten very far.

plugins/configs/api/listener.go Outdated Show resolved Hide resolved
plugins/configs/api/listener.go Outdated Show resolved Hide resolved
func (s *ConfigAPIService) pluginStatus(w http.ResponseWriter, req *http.Request) {
defer req.Body.Close()
id := mux.Vars(req)["id"]
if len(id) == 0 {
Copy link
Contributor

@sspaink sspaink Aug 6, 2021

Choose a reason for hiding this comment

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

Should we also check to see if the ID matches the expected format? In the test there is a regex check like this: require.Regexp(t, `^[\da-f]{8}\d{8}$`, createResp.ID) not sure if there is a common function for this somewhere already.

plugins/configs/api/listener.go Outdated Show resolved Hide resolved
plugins/configs/api/listener.go Show resolved Hide resolved
@sspaink sspaink changed the title feat: Config api 2 BREAKING CHANGE: Config api 2 Aug 9, 2021
@sspaink sspaink changed the title BREAKING CHANGE: Config api 2 feat: Config api 2 Aug 9, 2021
int_test.sh Show resolved Hide resolved
}

type PluginConfig struct {
ID string `json:"id"` // unique identifer
Copy link
Contributor

Choose a reason for hiding this comment

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

The ID field doesn't seem to be used. Was it intended to hold a well known string to identify the plugin config in the database? It looks like storage.Save() now uses bolt namespace "config-api" and key "plugins" that does the same thing. Can we get rid of this field and merge PluginConfig and PluginConfigCreate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is used by ConfigAPIPlugin, and as far as I can tell it does and should serialize this ID value.

Copy link
Contributor

Choose a reason for hiding this comment

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

I can comment it out and telegraf builds without error. My IDE says there are no references to it. The string "id" is not present in plugins/configs/api/plugin.go (where ConfigAPIPlugin is defined).


// store state
if a.Storage != nil {
if err := a.Storage.Save("config-api", "plugins", &a.plugins); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Storage.Load() is called once on startup and Storage.Save() is called once on shutdown. Boltdb seems like overkill in this use case. Saving to JSON would work just as well and have the advantage of being human readable.

I assume you guys have more in mind for boltdb and storage plugins, maybe more robust approach to saving (like saving periodically or after every config change)? Can you share what you have in mind related to this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The storage is a plugin so we aren't ruling out a json storage plugin in the future. Storage either does or will get written to any time a plugin is added or removed. it's more like a db in that you can write individual records instead of rewriting the whole file every time a single record changes.

Copy link
Contributor

Choose a reason for hiding this comment

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

When you say "Storage either does or will get written to any time a plugin is added or removed" I'm not sure we're looking at the same code. Like I said before, Storage.Save() is called once at shutdown. It's not called anywhere else outside of a unit test.

If you have plans for this to work differently in the future, we need you to communicate them somehow. It would be best to have in a design doc, but it at least needs to be commented in the code. Otherwise there's no way to do a meaningful review.

Comment on lines +68 to +84


+------------+ Processors and aggregators can be ordered +--------+
| Input +---+ and chained arbitrarily +--->+ Output |
+------------+ | | +--------+
| |
+------------+ | +-----------+ +------------+ +-----------+ +------------+ | +--------+
| Input +------>+ Processor +--->+ Aggregator +----->+ Processor +--->+ Aggregator +-->---->+ Output |
+------------+ | +-----------+ +------------+ +-----------+ +------------+ | +--------+
| |
+------------+ | | +--------+
| Input +---+ +--->+ Output |
+------------+ | | +--------+
| |
  +------------+ | | +--------+
  | Input      +---+ +--->+ Output |
  +------------+ +--------+
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 code format this? when it gets converted to markdown the diagram gets all funky.

@sspaink sspaink closed this Mar 1, 2022
@powersj powersj deleted the config-api-2 branch January 20, 2023 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants