diff --git a/containers/package-lock.json b/containers/package-lock.json index 5a1aa38e..ea40dc32 100644 --- a/containers/package-lock.json +++ b/containers/package-lock.json @@ -1,12 +1,12 @@ { "name": "@winglibs/containers", - "version": "0.0.21", + "version": "0.0.23", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@winglibs/containers", - "version": "0.0.21", + "version": "0.0.23", "license": "MIT", "dependencies": { "@cdktf/provider-aws": "^18.0.5", diff --git a/containers/package.json b/containers/package.json index 7935a6b6..500c357e 100644 --- a/containers/package.json +++ b/containers/package.json @@ -1,6 +1,6 @@ { "name": "@winglibs/containers", - "version": "0.0.22", + "version": "0.0.23", "description": "Container support for Wing", "repository": { "type": "git", diff --git a/containers/workload.sim.w b/containers/workload.sim.w index 2870b3a4..d8aba665 100644 --- a/containers/workload.sim.w +++ b/containers/workload.sim.w @@ -8,7 +8,6 @@ bring "./utils.w" as utils; pub class Workload_sim { publicUrlKey: str?; internalUrlKey: str?; - containerIdKey: str; pub publicUrl: str?; pub internalUrl: str?; @@ -18,12 +17,12 @@ pub class Workload_sim { imageTag: str; public: bool; state: sim.State; - + new(props: api.WorkloadProps) { this.appDir = utils.entrypointDir(this); this.props = props; this.state = new sim.State(); - this.containerIdKey = "container_id"; + let containerName = util.uuidv4(); let hash = utils.resolveContentHash(this, props); if let hash = hash { @@ -50,109 +49,117 @@ pub class Workload_sim { this.internalUrlKey = key; } - let s = new cloud.Service(inflight () => { - this.start(); - return () => { this.stop(); }; - }); - - std.Node.of(s).hidden = true; - std.Node.of(this.state).hidden = true; - } - - inflight start(): void { - log("starting workload..."); + let containerService = new cloud.Service(inflight () => { + log("starting workload..."); - let opts = this.props; + let opts = this.props; - // if this a reference to a local directory, build the image from a docker file - if utils.isPathInflight(opts.image) { - // check if the image is already built - try { - utils.shell("docker", ["inspect", this.imageTag]); - log("image {this.imageTag} already exists"); - } catch { - log("building locally from {opts.image} and tagging {this.imageTag}..."); - utils.shell("docker", ["build", "-t", this.imageTag, opts.image], this.appDir); - } - } else { - try { - utils.shell("docker", ["inspect", this.imageTag]); - log("image {this.imageTag} already exists"); - } catch { - log("pulling {this.imageTag}"); - utils.shell("docker", ["pull", this.imageTag]); + // if this a reference to a local directory, build the image from a docker file + if utils.isPathInflight(opts.image) { + // check if the image is already built + try { + utils.shell("docker", ["inspect", this.imageTag]); + log("image {this.imageTag} already exists"); + } catch { + log("building locally from {opts.image} and tagging {this.imageTag}..."); + utils.shell("docker", ["build", "-t", this.imageTag, opts.image], this.appDir); + } + } else { + try { + utils.shell("docker", ["inspect", this.imageTag]); + log("image {this.imageTag} already exists"); + } catch { + log("pulling {this.imageTag}"); + utils.shell("docker", ["pull", this.imageTag]); + } } - } - // start the new container - let dockerRun = MutArray[]; - dockerRun.push("run"); - dockerRun.push("--detach"); + // start the new container + let dockerRun = MutArray[]; + dockerRun.push("run"); + dockerRun.push("--detach"); + dockerRun.push("--rm"); - if let port = opts.port { - dockerRun.push("-p"); - dockerRun.push("{port}"); - } + dockerRun.push("--name", containerName); - if let env = opts.env { - if env.size() > 0 { - dockerRun.push("-e"); - for k in env.keys() { - dockerRun.push("{k}={env.get(k)!}"); - } + if let port = opts.port { + dockerRun.push("-p"); + dockerRun.push("{port}"); } - } - - dockerRun.push(this.imageTag); - if let runArgs = this.props.args { - for a in runArgs { - dockerRun.push(a); + if let env = opts.env { + if env.size() > 0 { + dockerRun.push("-e"); + for k in env.keys() { + dockerRun.push("{k}={env.get(k)!}"); + } + } } - } - log("starting container from image {this.imageTag}"); - log("docker {dockerRun.join(" ")}"); - let containerId = utils.shell("docker", dockerRun.copy()).trim(); - this.state.set(this.containerIdKey, containerId); + dockerRun.push(this.imageTag); - log("containerId={containerId}"); + if let runArgs = this.props.args { + for a in runArgs { + dockerRun.push(a); + } + } - let out = Json.parse(utils.shell("docker", ["inspect", containerId])); + log("starting container from image {this.imageTag}"); + log("docker {dockerRun.join(" ")}"); + utils.shell("docker", dockerRun.copy()); + + log("containerName={containerName}"); + + return () => { + utils.shell("docker", ["rm", "-f", containerName]); + }; + }) as "ContainerService"; + std.Node.of(containerService).hidden = true; + + let readinessService = new cloud.Service(inflight () => { + let opts = this.props; + let var out: Json? = nil; + util.waitUntil(inflight () => { + try { + out = Json.parse(utils.shell("docker", ["inspect", containerName])); + return true; + } catch { + log("something went wrong"); + return false; + } + }, interval: 0.1s); - if let port = opts.port { - let hostPort = out.tryGetAt(0)?.tryGet("NetworkSettings")?.tryGet("Ports")?.tryGet("{port}/tcp")?.tryGetAt(0)?.tryGet("HostPort")?.tryAsStr(); - if !hostPort? { - throw "Container does not listen to port {port}"; - } + if let port = opts.port { + let hostPort = out?.tryGetAt(0)?.tryGet("NetworkSettings")?.tryGet("Ports")?.tryGet("{port}/tcp")?.tryGetAt(0)?.tryGet("HostPort")?.tryAsStr(); + if !hostPort? { + throw "Container does not listen to port {port}"; + } - let publicUrl = "http://localhost:{hostPort!}"; + let publicUrl = "http://localhost:{hostPort!}"; - if let k = this.publicUrlKey { - this.state.set(k, publicUrl); - } + if let k = this.publicUrlKey { + this.state.set(k, publicUrl); + } - if let k = this.internalUrlKey { - this.state.set(k, "http://host.docker.internal:{hostPort!}"); - } + if let k = this.internalUrlKey { + this.state.set(k, "http://host.docker.internal:{hostPort!}"); + } - if let readiness = opts.readiness { - let readinessUrl = "{publicUrl}{readiness}"; - log("waiting for container to be ready: {readinessUrl}..."); - util.waitUntil(inflight () => { - try { - return http.get(readinessUrl).ok; - } catch { - return false; - } - }, interval: 0.1s); + if let readiness = opts.readiness { + let readinessUrl = "{publicUrl}{readiness}"; + log("waiting for container to be ready: {readinessUrl}..."); + util.waitUntil(inflight () => { + try { + return http.get(readinessUrl).ok; + } catch { + return false; + } + }, interval: 0.1s); + } } - } - } + }) as "ReadinessService"; + std.Node.of(readinessService).hidden = true; - inflight stop() { - let containerId = this.state.get(this.containerIdKey).asStr(); - log("stopping container {containerId}"); - utils.shell("docker", ["rm", "-f", containerId]); + std.Node.of(this.state).hidden = true; } -} \ No newline at end of file +}