-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
xk6 plugin integration #1688
xk6 plugin integration #1688
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1688 +/- ##
=======================================
Coverage 71.42% 71.43%
=======================================
Files 176 177 +1
Lines 13681 13698 +17
=======================================
+ Hits 9772 9785 +13
- Misses 3298 3301 +3
- Partials 611 612 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my initial look at this I think ... that 95% of this is not needed.
I was more thinking of just adding a function that changes the current module map and use that in the plugins.
I would even argue that it shouldn't check (at least for now) that someone tries to add "totally/not/valid/path" as ... well that is their problem ;)
This whole thing looks like it tries to be way too complex for what we want from the current js plugins for no added benefit but more code that the "plugins" need to write and it is slightly harder for them to just be copied in k6 once we decided they should be part of it.
Additionally I am pretty sure the sql module has a k6Module function in js with this code, which obviously can be fixed in the bridge or through some other means ... but IMO is again .. not needed
Thanks @mstoykov. This is already a cut-down version of Caddy plugins, but I left what's currently here as open design questions since we didn't really spec out the feature past "do what xcaddy does" 😄 You're right that Caddy modules/plugins are much broader in scope than what we need, but I don't think there's much complexity here, it's mostly just namespace handling and getters. OK, so to summarize:
On the topic of naming, should we abandon the "module" naming used by Caddy and use "plugin" instead? Caddy's naming is a bit confusing, but given the additional scope "modules" makes more sense in their case, whereas we could be fine with referring to them as "plugins" altogether. |
Diclaimer: this is a very preliminary comment, since I have only skimmed this PR and taken a glance at xk6. But, from what I can see, I will probably agree with @mstoykov that this is unnecessarily complex. Take for example the import plugin from 'k6/x/awesome-plugin';
plugin.provision() // maybe call this in setup() even? Instead of I think it's still early to tell exactly how the final k6 plugin API should look like, so the more minimal it is right now, the fewer breaking changes we'll have to make in the future. All of these interfaces are optional extra features that we can add in the future, in a backwards-compatible way, right? So we should probably skip them, for now, and add them properly when we see a clear need for them.
Not sure if that is the best way to distinguish between plugin types. Wouldn't interfaces be better? Seems like a much cleaner and type-safe alternative than relying on stringy checks |
d40e45b
to
ad3311d
Compare
am I correct in thinking that the move of all the current modules in I am not particularly strongly opinionated on whether or not they should be in |
ad3311d
to
b596c80
Compare
@mstoykov You're correct, moving all modules to I'll squash everything into a single commit before merging, as there was a lot of experimentation here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but drop the html
changes that were leftover and .. maybe squash this now in one commit?
//nolint:gochecknoglobals | ||
var ( | ||
modules = make(map[string]interface{}) | ||
mx sync.RWMutex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I am not certain having a Lock is truly necessary as the Register happens in init functions and I would argue should not happen at any other time. And the inits are by definition not concurrent so 🤷
Don't get me wrong ... it is probably better to have lock in the case that we ever decide to have Register outside the init
functons. And I doubt the RLock
significantly slows anything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I wasn't aware init()
s weren't concurrent.
I don't feel strongly about it to remove it, but if it's YAGNI then we might as well do so.
@na-- What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it matters much - it shouldn't be needed, but it won't slow down anything either, so 🤷♂️
js/modules/modules.go
Outdated
if !strings.HasPrefix(name, extPrefix) { | ||
name = fmt.Sprintf("%s%s", extPrefix, name) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of wonder if we shouldn't just either:
- always prefix it
- panic if it isn't prefixed instead of prefixing it.
My reasoning is that if someone writes Register("k7/x/something")
and then goes to use their module they will be really surprised that it totally doesn't work. While if it panics or the documentation specifically says taht we always prepend k6/x/
that will be much better IMO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hhmm well the function comment does explain that imports will be in the form k6/x/<name>
, and this gives the option to register with or without it. I can see how panicking would be helpful though, but not sure if we should force users to specify the prefix. Kind of torn on this one...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to just ask for the category and the name (net/rtp
) and always prepend the prefix (k6/x/
) ourselves. We can simply mention this approach in the docs and our reasoning would be that it is the intended behavior. Then there's no need for panic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Automatically adding prefixes will likely just lead to more confusion.
I'm thinking that manual import path config + Panics would be preferable as:
- The error tells the user how to solve it.
- No hidden behavior you need to know or document.
- Import path in the JS file will match exactly what they have written in their plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, @simskij convinced me, panic
it is. 😄
Will push the change in a bit.
@mostafa Asking for the category would be interesting, and similar to xcaddy's namespaces. Right now the consensus is that it doesn't seem necessary for this PoC, but if it becomes a requirement in the future then it would be difficult to change the existing API, so I'm on the fence about it. @na-- @mstoykov What are your thoughts about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as before I don't think categories are needed for k6. I find the "we have different module registers and functions for different categories" approach much better and easier to document and easy for the people who want add 1 type of plugin to not have to read how it's done for the others.
We can always add a more central plugin system and wire the old calls to it and recommend that people use the new system ... although again ... I highly doubt this day will come
b596c80
to
6b7fe83
Compare
This adds plugin support to k6 inspired by xcaddy[1]. See the xk6 repo[2]. Closes #1353 [1]: https://github.com/caddyserver/xcaddy [2]: https://github.com/k6io/xk6
6b7fe83
to
a7dbe3f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm why do we need internal/modules
at all? From what I can see, there's nothing stopping a JS plugin from directly calling internal/modules.Register("k6/non-x-path")
, right?
Wouldn't it be both simpler and more secure to have something like this in the old js/modules/index.go
file?
var modules = map[string]interface{}{
"k6": k6.New(),
"k6/crypto": crypto.New(),
"k6/crypto/x509": x509.New(),
"k6/encoding": encoding.New(),
"k6/http": http.New(),
"k6/metrics": metrics.New(),
"k6/html": html.New(),
"k6/ws": ws.New(),
"k6/protocols/grpc": grpc.New(),
}
const extPrefix string = "k6/x/"
func Get(name string) interface{} {
return modules[name]
}
func Register(name string, mod interface{}) {
if !strings.HasPrefix(name, extPrefix) {
panic(fmt.Errorf("external module names must be prefixed with '%s', tried to register: %s", extPrefix, name))
}
modules[name] = mod
}
The built-in k6 modules would be an immutable static map and and you can only add modules starting with k6/x
, while you can get any module?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know about this... 😊 Live and learn, I guess - LGTM!
This is a proposal for an external plugin system for k6, inspired by xcaddy. See also the xk6 repo and the SQL plugin adapted from @mostafa's Go plugin version.
Initially plugins are only meant for external JS modules, but support for other plugin types (output, etc.) is likely to be added in the future.
The module support in (x)caddy is much broader in scope than what's currently in this PoC. The main distinction is that Caddy modules can recursively load other modules, and only the "guest"/"child" modules are referred to as "plugins". See the documentation.
Usage
To build a
k6
binary with the SQL plugin, from thexk6
repo @11baed0
run:CGO_ENABLED=1
is required for the SQL dependencies.With the following
script.js
:Running
./k6 run script.js
should create atest.sqlite
DB and showINFO[0000] key: plugin-name, value: k6-plugin-sql source=console
.Closes #1353