Skip to content

Commit

Permalink
feat(sdk): network and entrypoint options for sim.Container (#6667)
Browse files Browse the repository at this point in the history
## Checklist

- [ ] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [ ] Description explains motivation and solution
- [ ] Tests added (always)
- [ ] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
eladcon authored Jun 13, 2024
1 parent 18a0112 commit a80272e
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 2 deletions.
37 changes: 37 additions & 0 deletions docs/docs/04-standard-library/sim/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,9 @@ let ContainerProps = sim.ContainerProps{ ... };
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.name">name</a></code> | <code>str</code> | A name for the container. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.args">args</a></code> | <code>MutArray&lt;str&gt;</code> | Container arguments. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.containerPort">containerPort</a></code> | <code>num</code> | Internal container port to expose. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.entrypoint">entrypoint</a></code> | <code>str</code> | Container entrypoint. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.env">env</a></code> | <code>MutMap&lt;str&gt;</code> | Environment variables to set in the container. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.network">network</a></code> | <code>str</code> | Docker network to use for the container - such as 'host', 'bridge', etc. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.sourceHash">sourceHash</a></code> | <code>str</code> | An explicit source hash that represents the container source. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.sourcePattern">sourcePattern</a></code> | <code>str</code> | A glob of local files to consider as input sources for the container, relative to the build context directory. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.volumes">volumes</a></code> | <code>MutArray&lt;str&gt;</code> | Volume mount points. |
Expand Down Expand Up @@ -783,6 +785,19 @@ Internal container port to expose.

---

##### `entrypoint`<sup>Optional</sup> <a name="entrypoint" id="@winglang/sdk.sim.ContainerProps.property.entrypoint"></a>

```wing
entrypoint: str;
```

- *Type:* str
- *Default:* default image entrypoint

Container entrypoint.

---

##### `env`<sup>Optional</sup> <a name="env" id="@winglang/sdk.sim.ContainerProps.property.env"></a>

```wing
Expand All @@ -796,6 +811,28 @@ Environment variables to set in the container.

---

##### `network`<sup>Optional</sup> <a name="network" id="@winglang/sdk.sim.ContainerProps.property.network"></a>

```wing
network: str;
```

- *Type:* str
- *Default:* default docker network

Docker network to use for the container - such as 'host', 'bridge', etc.

> [https://docs.docker.com/network.](https://docs.docker.com/network.)
---

*Example*

```wing
'host'
```


##### `sourceHash`<sup>Optional</sup> <a name="sourceHash" id="@winglang/sdk.sim.ContainerProps.property.sourceHash"></a>

```wing
Expand Down
37 changes: 37 additions & 0 deletions docs/docs/04-standard-library/sim/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,9 @@ let ContainerProps = sim.ContainerProps{ ... };
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.name">name</a></code> | <code>str</code> | A name for the container. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.args">args</a></code> | <code>MutArray&lt;str&gt;</code> | Container arguments. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.containerPort">containerPort</a></code> | <code>num</code> | Internal container port to expose. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.entrypoint">entrypoint</a></code> | <code>str</code> | Container entrypoint. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.env">env</a></code> | <code>MutMap&lt;str&gt;</code> | Environment variables to set in the container. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.network">network</a></code> | <code>str</code> | Docker network to use for the container - such as 'host', 'bridge', etc. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.sourceHash">sourceHash</a></code> | <code>str</code> | An explicit source hash that represents the container source. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.sourcePattern">sourcePattern</a></code> | <code>str</code> | A glob of local files to consider as input sources for the container, relative to the build context directory. |
| <code><a href="#@winglang/sdk.sim.ContainerProps.property.volumes">volumes</a></code> | <code>MutArray&lt;str&gt;</code> | Volume mount points. |
Expand Down Expand Up @@ -292,6 +294,19 @@ Internal container port to expose.

---

##### `entrypoint`<sup>Optional</sup> <a name="entrypoint" id="@winglang/sdk.sim.ContainerProps.property.entrypoint"></a>

```wing
entrypoint: str;
```

- *Type:* str
- *Default:* default image entrypoint

Container entrypoint.

---

##### `env`<sup>Optional</sup> <a name="env" id="@winglang/sdk.sim.ContainerProps.property.env"></a>

```wing
Expand All @@ -305,6 +320,28 @@ Environment variables to set in the container.

---

##### `network`<sup>Optional</sup> <a name="network" id="@winglang/sdk.sim.ContainerProps.property.network"></a>

```wing
network: str;
```

- *Type:* str
- *Default:* default docker network

Docker network to use for the container - such as 'host', 'bridge', etc.

> [https://docs.docker.com/network.](https://docs.docker.com/network.)
---

*Example*

```wing
'host'
```


##### `sourceHash`<sup>Optional</sup> <a name="sourceHash" id="@winglang/sdk.sim.ContainerProps.property.sourceHash"></a>

```wing
Expand Down
2 changes: 1 addition & 1 deletion examples/tests/sdk_tests/container/container.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ if util.env("WING_TARGET") == "sim" {
log(response.body);
expect.equal("Hello, Wingnuts!", response.body);
}

}
27 changes: 27 additions & 0 deletions examples/tests/sdk_tests/container/entrypoint.test.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*\
skipPlatforms:
- win32
- darwin
\*/

bring sim;
bring http;
bring util;
bring expect;

// only relevant in simulator
if util.env("WING_TARGET") == "sim" {
let entrypoint = new sim.Container(
name: "my-entrypoint-app",
image: "./my-docker-image",
containerPort: 3000,
args: ["-c", "RESPONSE=hello /usr/local/bin/node /app/index.js"],
entrypoint: "/bin/sh",
) as "with-entrypoint";

test "container with entrypoint" {
let response = http.get("http://localhost:{entrypoint.hostPort!}");
log(response.body);
expect.equal("hello", response.body);
}
}
4 changes: 3 additions & 1 deletion examples/tests/sdk_tests/container/my-docker-image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ process.on('SIGINT', () => {
process.exit(0)
});

const response = process.env.RESPONSE;

const server = http.createServer((req, res) => {
console.log(`request received: ${req.method} ${req.url}`);
res.end('Hello, Wingnuts!');
res.end(response ?? 'Hello, Wingnuts!');
});

console.log('listening on port 3000');
Expand Down
25 changes: 25 additions & 0 deletions examples/tests/sdk_tests/container/network.test.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*\
skipPlatforms:
- win32
- darwin
\*/

bring sim;
bring http;
bring util;
bring expect;

// only relevant in simulator
if util.env("WING_TARGET") == "sim" {
let networkHost = new sim.Container(
name: "http-echo",
image: "hashicorp/http-echo",
containerPort: 5678,
args: ["-text=bang"],
network: "host",
) as "network-host";

test "container with host network" {
expect.equal(networkHost.hostPort, "5678");
}
}
18 changes: 18 additions & 0 deletions libs/wingsdk/src/target-sim/container.inflight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export class Container implements IContainerClient, ISimulatorResourceInstance {
dockerRun.push("--rm");
dockerRun.push("--name", this.containerName);

if (this.props.network) {
dockerRun.push(`--network=${this.props.network}`);
}

if (this.props.containerPort) {
dockerRun.push("-p", this.props.containerPort.toString());
}
Expand Down Expand Up @@ -107,6 +111,11 @@ export class Container implements IContainerClient, ISimulatorResourceInstance {
}
}

if (this.props.entrypoint) {
dockerRun.push("--entrypoint");
dockerRun.push(this.props.entrypoint);
}

dockerRun.push(this.imageTag);

for (const a of this.props.args ?? []) {
Expand Down Expand Up @@ -143,6 +152,15 @@ export class Container implements IContainerClient, ISimulatorResourceInstance {

// if we are waiting for a port, check if the container is listening to it
if (this.props.containerPort) {
// when using the host network, the host port is the same as the container port
if (this.props.network === "host") {
hostPort = this.props.containerPort;
return (
container?.[0]?.Config?.ExposedPorts?.[`${hostPort}/tcp`] !==
undefined
);
}

hostPort =
container?.[0]?.NetworkSettings?.Ports?.[
`${this.props.containerPort}/tcp`
Expand Down
16 changes: 16 additions & 0 deletions libs/wingsdk/src/target-sim/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ export interface ContainerProps {
*/
readonly args?: string[];

/**
* Docker network to use for the container - such as 'host', 'bridge', etc.
* @link https://docs.docker.com/network.
* @default - default docker network
* @example 'host'
*/
readonly network?: string;

/**
* Container entrypoint
* @default - default image entrypoint
*/
readonly entrypoint?: string;

/**
* A glob of local files to consider as input sources for the container, relative to the build
* context directory.
Expand Down Expand Up @@ -115,6 +129,8 @@ export class Container extends Resource implements ISimulatorResource {
volumes: this.props.volumes,
args: this.props.args,
cwd: App.of(this).entrypointDir,
network: this.props.network,
entrypoint: this.props.entrypoint,
};
return {
type: SIM_CONTAINER_FQN,
Expand Down
2 changes: 2 additions & 0 deletions libs/wingsdk/src/target-sim/schema-resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ export interface ContainerSchema {
readonly volumes?: string[];
readonly args?: string[];
readonly cwd: string;
readonly network?: string;
readonly entrypoint?: string;
}

/** Runtime attributes for sim.Container */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# [entrypoint.test.w](../../../../../../examples/tests/sdk_tests/container/entrypoint.test.w) | compile | tf-aws

## main.tf.json
```json
{
"//": {
"metadata": {
"backend": "local",
"stackName": "root",
"version": "0.20.3"
},
"outputs": {}
},
"provider": {
"aws": [
{}
]
}
}
```

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# [entrypoint.test.w](../../../../../../examples/tests/sdk_tests/container/entrypoint.test.w) | test | sim

## stdout.log
```log
[INFO] container with entrypoint | hello
[WARNING] container with entrypoint | Timeout waiting for container root/env0/with-entrypoint to shutdown, removing forcefully
pass ─ entrypoint.test.wsim » root/env0/test:container with entrypoint
Tests 1 passed (1)
Snapshots 1 skipped
Test Files 1 passed (1)
Duration <DURATION>
```

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# [network.test.w](../../../../../../examples/tests/sdk_tests/container/network.test.w) | compile | tf-aws

## main.tf.json
```json
{
"//": {
"metadata": {
"backend": "local",
"stackName": "root",
"version": "0.20.3"
},
"outputs": {}
},
"provider": {
"aws": [
{}
]
}
}
```

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# [network.test.w](../../../../../../examples/tests/sdk_tests/container/network.test.w) | test | sim

## stdout.log
```log
pass ─ network.test.wsim » root/env0/test:container with host network
Tests 1 passed (1)
Snapshots 1 skipped
Test Files 1 passed (1)
Duration <DURATION>
```

0 comments on commit a80272e

Please sign in to comment.