-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
JSON targets format #300
JSON targets format #300
Conversation
This commit introduces the following changes in preparation for alternative target formats: - LazyTargeter renamed to LegacyTargeter - EagerTargeter refactored to take in any Targeter - `-format` flag added to the attack command - Extended documentation of the legacy target format
attack.go
Outdated
return err | ||
|
||
switch opts.format { | ||
case "json": |
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.
string json
has 3 occurrences, make it a constant
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.
Agree, should be constants.
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, I'll make some constants for these values.
@tsenart I like the approach taken here. I think it's much cleaner creating a new format than trying to find an ugly way to fit this feature into the |
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.
This proposal is sound to the bone. The only gripe I have is with the naming of the formats. While json
communicates the expected input format, legacy
implies lifecycle. There are certainly perceived limitations for the current format, yet it might serve well for a good amount of use-cases. So I'd propose to give it a name which aligns well e.g.: plain
, text
or something similar.
README.md
Outdated
|
||
##### `legacy` format | ||
|
||
The ill-defined legacy format almost resembles the plain-text HTTP message format but |
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.
In here ill-defined
seems self-deprecating, could be left out.
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, agree there's no need to deprecate it. I'll change the wording.
attack.go
Outdated
@@ -25,6 +25,7 @@ func attackCmd() command { | |||
|
|||
fs.StringVar(&opts.name, "name", "", "Attack name") | |||
fs.StringVar(&opts.targetsf, "targets", "stdin", "Targets file") | |||
fs.StringVar(&opts.format, "format", "legacy", "Targets format [legacy, json]") |
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.
Defaults could be constants.
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.
They could. I'll make this change together with the other constant related changes.
attack.go
Outdated
return err | ||
|
||
switch opts.format { | ||
case "json": |
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.
Agree, should be constants.
attack.go
Outdated
tr = vegeta.NewJSONTargeter(src, body, hdr) | ||
case "legacy": | ||
fallthrough | ||
default: |
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.
The user should get feedback for wrong inputs, would move this up to the case where it belongs and error for everything else.
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.
Yep, this implementation was rather incomplete in view of getting earlier feedback. I'll add proper validation as well as tests.
README.md
Outdated
|
||
The JSON format makes integration with programs that produce targets dynamically easier. | ||
Each target is one JSON object in its own line. If present, the body field must be base64 encoded. | ||
|
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.
This section should be expanded with the fileds of the json objects, which are mandatory and which are optional.
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.
+1. What do you think of checking in a JSON schema file for this? Is it over-kill?
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.
That's a great idea, especially with such small surface,maintaining such a file will be great for documentation and potential integrations.
lib/targets.go
Outdated
Method string `json:"method"` | ||
URL string `json:"url"` | ||
Body []byte `json:"body"` | ||
Header http.Header `json:"header"` |
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.
Always uncertain which one is canonical Header
or Headers
.
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.
An HTTP message has a Header and a Body. A Header containers many "Headers". Yes, it's confusing. What naming do you think we should stick to?
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.
Usually I consult the rfc and it's consistently referring to that part of request/response as header, so all good here. :>
@xla: So, what do you prefer? |
-reporter string | ||
Reporter [text, json, plot, hist[buckets]] (default "text") | ||
``` | ||
### report command |
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.
Any particular reason why you have removed the explanation of report
and dump
command?
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.
Because it was redundant. It's already included in the output of vegeta -h
.
Imo, the drawback of proposed api is that body payloads are not in plain text (base64 encoded). As an alternative, maybe yaml format can be used as an "envelope", this way allowing to put unescaped body payloads. Or, you may re-consider the idea with HTTP/1.x message format. For example, the approach used in REST client tools (with inline body payloads and
This would also make |
@1u0 Thanks for bringing that seemingly popular format to our attention! I wasn't aware of it personally. Do you know if it's more formally specified somewhere? What are its origins? The only issue I can see is that framing scheme doesn't allow for request bodies to contain that same separator Regarding the JSON format, it isn't clear from what you wrote why you find the need to Base64 encode the request bodies a drawback. Could you show us how it hinders you so that we understand your context better? |
A potential use case can be that payload was generated (persisted into a file) and passed to About the
|
You don't need
Yeah, indeed a tradeoff. I suppose if it's well documented, then it shouldn't be a problem for people. So I'd be on-board with also adding this functionality to the HTTP-like format, but I'm wondering if breaking back-wards compatibility in this particular case is worth it. I'm not very sure. What's your take @xla? |
Ha! |
I'd focus on the proposed change for the json format at first and keep the additonal changes to the existing format as potential improvement for the backlog and evaluate in depth if the change is indeed breaking. The disucssion around encoding of payload bodies seems moot as any sensible human interaction with formats like json needs specific tooling, as much as it is necessary to interact with large amounts of newline delimited plain text. It should not so much inform the design of the implementation as it seems reasonable to assume that the majoirty of interactions with the json definitions come from machine owned pipelines, basically supporting your claim @tsenart that json targets are generated for the most part. |
+1 |
internal/cmd/jsonschema/main.go
Outdated
typ := fs.String("type", "", fmt.Sprintf("Vegeta type to generate a JSON schema for [%s]", valid)) | ||
out := fs.String("output", "stdout", "Output file") | ||
|
||
fs.Parse(os.Args[1:]) |
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.
Error return value of fs.Parse
is not checked
@xla: Assigned to you. PTAL again. |
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.
👍 🍡
Minor style nits. :>
@@ -25,6 +26,8 @@ func attackCmd() command { | |||
|
|||
fs.StringVar(&opts.name, "name", "", "Attack name") | |||
fs.StringVar(&opts.targetsf, "targets", "stdin", "Targets file") | |||
fs.StringVar(&opts.format, "format", vegeta.HTTPTargetFormat, | |||
fmt.Sprintf("Targets format [%s]", strings.Join(vegeta.TargetFormats, ", "))) |
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 find this breaking odd, it doesn't give consistent guidance how to break long lines and makes it hard to edit. Might be preferrable to use the following rule:
func myFunc(
param1,
param2,
param3,
)
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.
Let's discuss this today in our pairing session.
case vegeta.HTTPTargetFormat: | ||
tr = vegeta.NewHTTPTargeter(src, body, hdr) | ||
default: | ||
return fmt.Errorf("format %q isn't one of [%s]", |
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.
Same as above.
case t == nil || other == nil: | ||
return false | ||
default: | ||
equal := t.Method == other.Method && |
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.
Guess this is for readability, would argue just as hard to read in the if statement itself.
This feature has been looooooong in the making. Since #148, namely. Feels good to make progress again :-) |
By feature, I mean in-line response bodies which JSON targets make easy peasy. |
Hey @tsenart , what's the status of this feature? Is it merged already? |
Yes.
Sent via Superhuman iOS ( https://sprh.mn/?vip=tsenart@gmail.com )
…On Thu, Apr 23 2020 at 5:03 PM, Omkar Jadhav < ***@***.*** > wrote:
Hey @tsenart ( https://github.com/tsenart ) , what's the status of this
feature? Is it merged already?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub (
#300 (comment) ) , or unsubscribe
(
https://github.com/notifications/unsubscribe-auth/AAAQPDZ2PMHFBJHH55IYA6TROBKE7ANCNFSM4FHWJ74Q
).
|
Background
The original targets format closely resembles plain HTTP/1.x messages. It was meant to be used by humans writing those targets directly on their terminals. With its lack of support for in-line body definitions, this ill-defined legacy format made Vegeta hard to integrate with other programs generating dynamic targets on the fly with distinct request bodies.
Extending the legacy format to support arbitrary in-line request bodies would require further deviation from the HTTP/1.x message format since, to the best of my knowledge, there is no official plain text framing format that would allow the boundaries between multiple targets with arbitrary request bodies to be easily recognized (and hence, parsed).
It could be done, certainly, but for the use case of integrating Vegeta with other programs generating targets, I think a simpler alternative JSON based format could be better.
This PR proposes just such a format and is intended to gather feedback from interested parties.
It's currently a work-in-progress, but the CLI interface is already specified and documented.
Please provide feedback: @coxx, @1u0, @mbrookes1304, @cwinters, @xla.
Related Issues and PRs
Checklist