k6 v0.29.0 is here! :tada: It's a feature-packed release with tons of much-requested changes and additions, a lot of them implemented by awesome external contributors! :heart:

As promised in the previous release notes, we're trying to stick to a roughly 8-week release cycle, so you can expect the next k6 version at the start of January 2021, barring any bugfix releases before that.

## New features

### Initial support for gRPC ([#1623](https://github.com/loadimpact/k6/pull/1623))

k6 now supports unary gRPC calls via the new `k6/net/grpc` built-in module. Streaming RPCs are not yet supported and the **JS API is in beta**, so there might be slight breaking changes to the API in future k6 versions, but it's a good start on the road to fully supporting this much-requested protocol!

This is a simple example of how the new module can be used with [grpcb.in](https://grpcb.in/):
```js
import grpc from "k6/net/grpc";

let client = new grpc.Client();
// Download addsvc.proto for https://grpcb.in/, located at:
// https://raw.githubusercontent.com/moul/pb/master/addsvc/addsvc.proto
// and put it in the same folder as this script.
client.load(null, "addsvc.proto");

export default () => {
    client.connect("grpcb.in:9001", { timeout: "5s" });

    let response = client.invoke("addsvc.Add/Sum", {
        a: 1,
        b: 2
    });
    console.log(response.message.v); // should print 3

    client.close();
}
```

You can find more information and examples how to use k6's new gRPC testing capabilities in [our documentation](https://k6.io/docs/javascript-api/k6-net-grpc).

Huge thanks to @rogchap for adding this feature!

### New options for configuring DNS resolution ([#1612](https://github.com/loadimpact/k6/pull/1612))

You can now control some aspects of how k6 performs DNS resolution! Previously, k6 would have cached DNS responses indefinitely ([#726](https://github.com/loadimpact/k6/issues/726)) and always picked the first resolved IP ([#738](https://github.com/loadimpact/k6/issues/738)) for all connections. This caused issues, especially when load testing services that relied on DNS for load-balancing or auto-scaling.

For technical reasons explored in ([#726](https://github.com/loadimpact/k6/issues/726)), k6 v0.29.0 still doesn't respect the actual TTL value of resolved IPs, that will be fixed in a future k6 version. For now, it simply allows users to specify a global static DNS TTL value and resolution strategy manually. It also has better defaults! Now, by default, the global DNS TTL value is 5 minutes and, if the DNS resolution returned multiple IPs, k6 will pick a random (preferably IPv4) one for each connection.

You can also configure this behavior with the new `--dns` CLI flag, the `K6_DNS` environment variable, or the `dns` script/JSON option. Three DNS resolution options are exposed in this k6 version: `ttl`, `select`, and `policy`.

Possible `ttl` values are :
- `0`: no caching at all - each request will trigger a new DNS lookup.
- `inf`: cache any resolved IPs for the duration of the test run _(the old k6 behavior)_.
- any time duration like `60s`, `5m30s`, `10m`, `2h`, etc.; if no unit is specified (e.g. `ttl=3000`), k6 assumes milliseconds. _The new default value is `5m`._

Possible `select` values are:
- `first` - always pick the first resolved IP _(the old k6 behavior)_.
- `random` - pick a random IP for every new connection _(the new default value)_.
- `roundRobin` - iterate sequentially over the resolved IPs.

Possible `policy` values are:
- `preferIPv4`: use IPv4 addresses, if available, otherwise fall back to IPv6 _(the new default value)_.
- `preferIPv6`: use IPv6 addresses, if available, otherwise fall back to IPv4.
- `onlyIPv4`: only use IPv4 addresses, ignore any IPv6 ones.
- `onlyIPv6`: only use IPv6 addresses, ignore any IPv4 ones.
- `any`: no preference, use all addresses _(the old k6 behavior)_.

Here are some configuration examples:

```bash
k6 run --dns "ttl=inf,select=first,policy=any" script.js # this is the old k6 behavior
K6_DNS="select=random,ttl=5m,policy=preferIPv4" k6 cloud script.js # new default behavior
# syntax for the JSON config file or for the exported script `options`:
echo '{"dns": {"select": "roundRobin", "ttl": "1h33m7s", "policy": "onlyIPv6"}}' > config.json
k6 run --config "config.json" script.js
```

### Support for Go extensions ([#1688](https://github.com/loadimpact/k6/pull/1688))

After some discussions ([#1353](https://github.com/loadimpact/k6/issues/1353)) and exploration of different approaches for Go-based k6 extensions, we've settled on adopting something very similar to [caddy's extensions](https://caddyserver.com/docs/extending-caddy). In short, [`xk6`](https://github.com/k6io/xk6) (modeled after [`xcaddy`](https://github.com/caddyserver/xcaddy)) is a small stand-alone tool that will be able to build custom k6 binaries with 3rd party extensions bundled in. The extensions can be simple Git repositories (no central infrastructure needed!) with Go modules. They will be fully compiled, not interpreted, a part of the final custom k6 binary users will be able to build with k6.

xk6 is not yet stable or documented, so any extension authors will struggle until we stabilize and document everything in the coming weeks. The important part is that the k6 changes that would allow xk6 to work were implemented in [#1688](https://github.com/loadimpact/k6/pull/1688), so k6 v0.29.0 is the first version compatible with xk6!

Expect more information soon, but for a brief example, xk6 will work somewhat like this:

```bash
xk6 build v0.29.0 --with github.com/k6io/xk6-k8s --with github.com/k6io/xk6-sql@v0.1.1

./k6 run some-script-with-sql-and-k8s.js
```

Thanks, @andremedeiros, for pushing us to add plugins in k6 and for making a valiant attempt to harness Go's poor plugin API! Thank you, @mardukbp, for pointing us towards the xcaddy approach and explaining its benefits!

### Support for setting local IPs, potentially from multiple NICs ([#1682](https://github.com/loadimpact/k6/pull/1682))

You can now specify a list of source IPs, IP ranges and CIDRs for `k6 run`, from which VUs will make requests via the new `--local-ips` CLI flag or `K6_LOCAL_IPS` environment variable. The IPs will be sequentially given out to VUs, allowing you to distribute load between different local addresses. This option doesn't change anything on the OS level, so the IPs need to already be configured on the OS level in order for k6 to be able to use them.

The biggest use case for this feature is splitting the network traffic from k6 between multiple network adapters, thus potentially greatly increasing the available network throughput. For example, if you have 2 NICs, you can run k6 with `--local-ips="<IP-from-first-NIC>,<IP-from-second-NIC>"` to balance the traffic equally between them - half of the VUs will use the first IP and the other half will use the second. This can scale to any number of NICs, and you can repeat some local IPs to give them more traffic. For example, `--local-ips="<IP1>,<IP2>,<IP3>,<IP3>"` will split VUs between 3 different source IPs in a 25%:25%:50% ratio.

Thanks to @ofauchon, @srguglielmo, and @divfor for working on previous iterations of this!

### New option for blocking hostnames ([#1666](https://github.com/loadimpact/k6/pull/1666))

You can now block network traffic by hostnames with the new `--block-hostnames` CLI flag / `K6_BLOCK_HOSTNAMES` environment variable / `blockHostnames` JS/JSON option. Wildcards are also supported at the beginning, allowing you to easily block a domain and all of its subdomains. For example, this will make sure k6 never attempts to connect to any `k6.io` subdomain (`test.k6.io`, `test-api.k6.io`, etc.) and `www.example.com`:

```js
export let options = {
  blockHostnames: ["*.k6.io" , "www.example.com"],
};
```

Thanks to @krashanoff for implementing this feature!

## UX and enhancements

- HTTP: The [gjson library](https://github.com/tidwall/gjson/) k6 uses for handling the HTTP `Response.json(selector)` behavior was updated, so we now support more [modifiers](https://github.com/tidwall/gjson/blob/master/SYNTAX.md#modifiers) like `@flatten` and multipaths ([#1626](https://github.com/loadimpact/k6/pull/1626)). Thanks, @sondnm!
- HTTP: The status text returned by the server can now be accessed from the new `Response.status_text` field ([#1649](https://github.com/loadimpact/k6/pull/1649)). Thanks, @lcd1232!
- HTTP: `--http-debug` now emits extra UUID values that can be used to match HTTP requests and their responses ([#1644](https://github.com/loadimpact/k6/pull/1644)). Thanks, @repl-david-winiarski!
- Logging: A new `allowedLabels` sub-option is added to the Loki configuration ([#1639](https://github.com/loadimpact/k6/pull/1639)).
- Cloud: when aborting a `k6 cloud` test with `Ctrl+C`, k6 will now wait for the cloud service to fully abort the test run before returning. A second `Ctrl+C` will cause it to immediately exit ([#1647](https://github.com/loadimpact/k6/pull/1647)), ([#1705](https://github.com/loadimpact/k6/pull/1705)). Thanks, @theerapatcha!
- JS: k6 will now attempt to recover from Go panics that occur in VU code, so they will be treated similarly to JS exceptions ([#1697](https://github.com/loadimpact/k6/pull/1697)). This is just a precaution that should never be needed. panics should not happen and if one occurs, please report it in our issue tracker, since it's most likely a bug in k6.

## Bugs fixed!

- JS: [goja](https://github.com/dop251/goja), the JS runtime k6 uses, was updated to its latest version, to fix some issues with regular expressions after its previous update ([#1707](https://github.com/loadimpact/k6/pull/1707)).
- JS: Prevent loops with `--compatibility-mode=extended` when Babel can transpile the code but goja can't parse it ([#1651](https://github.com/loadimpact/k6/pull/1651)).
- JS: Fixed a bug that rarely caused a `context canceled` error message to be shown ([#1677](https://github.com/loadimpact/k6/pull/1677)).
- HTTP: Setting an empty `userAgent` option caused k6 to revert to the default Go `User-Agent` header value of `Go-http-client`. Now something like `--user-agent=''` will cause k6 to not send the `User-Agent` header at all ([#1695](https://github.com/loadimpact/k6/pull/1695)).
- Cloud: `k6 cloud --quiet` didn't just hide the progressbar, but caused the k6 process to exit as soon as the cloud test was created, without waiting for it to finish. `k6 cloud -q` is now fixed to be similar to the `k6 run -q` behavior, but if the old behavior was wanted, something close to it can be recreated by using `k6 cloud --exit-on-running` ([#1702](https://github.com/loadimpact/k6/pull/1702)).

## Internals

- We switched to GitHub Actions for our CI ([#1640](https://github.com/loadimpact/k6/pull/1640)).
- We've updated to Go 1.15 for building the official k6 binary releases ([#1679](https://github.com/loadimpact/k6/pull/1679))

## Breaking changes

- As mentioned above, DNS resolution defaults were changed. If you want to use the old k6 behavior of always picking the first IP, no IPv4 preference, and caching DNS responses indefinitely, run k6 with `--dns="ttl=inf,select=first,policy=any"`.
