Skip to content

Commit

Permalink
fix(cli): allow empty path when calling services via garden call
Browse files Browse the repository at this point in the history
  • Loading branch information
edvald committed Jul 31, 2018
1 parent e20f030 commit b5d4972
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 16 deletions.
47 changes: 32 additions & 15 deletions garden-cli/src/commands/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import {
import { splitFirst } from "../util/util"
import { ParameterError, RuntimeError } from "../exceptions"
import { EntryStyle } from "../logger/types"
import { pick } from "lodash"
import { pick, find } from "lodash"
import { PluginContext } from "../plugin-context"
import { ServiceEndpoint } from "../types/service"
import dedent = require("dedent")

export const callArgs = {
Expand Down Expand Up @@ -52,7 +53,6 @@ export class CallCommand extends Command<typeof callArgs> {

async action(ctx: PluginContext, args: Args): Promise<CommandResult> {
let [serviceName, path] = splitFirst(args.serviceAndPath, "/")
path = "/" + path

// TODO: better error when service doesn't exist
const service = await ctx.getService(serviceName)
Expand All @@ -73,24 +73,41 @@ export class CallCommand extends Command<typeof callArgs> {
}

// find the correct endpoint to call
let matchedEndpoint
let matchedEndpoint: ServiceEndpoint | null = null
let matchedPath

for (const endpoint of status.endpoints) {
// we can't easily support raw TCP or UDP in a command like this
if (endpoint.protocol !== "http" && endpoint.protocol !== "https") {
continue
// we can't easily support raw TCP or UDP in a command like this
const endpoints = status.endpoints.filter(e => e.protocol === "http" || e.protocol === "https")

if (!path) {
// if no path is specified and there's a root endpoint (path === "/") we use that
const rootEndpoint = <ServiceEndpoint>find(endpoints, e => e.paths && e.paths.includes("/"))

if (rootEndpoint) {
matchedEndpoint = rootEndpoint
matchedPath = "/"
} else {
// if there's no root endpoint, pick the first endpoint
matchedEndpoint = endpoints[0]
matchedPath = endpoints[0].paths ? endpoints[0].paths![0] : ""
}

if (endpoint.paths) {
for (const endpointPath of endpoint.paths) {
if (path.startsWith(endpointPath) && (!matchedPath || endpointPath.length > matchedPath.length)) {
matchedPath = endpointPath
matchedEndpoint = endpoint
path = matchedPath

} else {
path = "/" + path

for (const endpoint of status.endpoints) {
if (endpoint.paths) {
for (const endpointPath of endpoint.paths) {
if (path.startsWith(endpointPath) && (!matchedPath || endpointPath.length > matchedPath.length)) {
matchedPath = endpointPath
matchedEndpoint = endpoint
}
}
} else if (!matchedPath) {
matchedEndpoint = endpoint
}
} else if (!matchedPath) {
matchedEndpoint = endpoint
}
}

Expand All @@ -102,7 +119,7 @@ export class CallCommand extends Command<typeof callArgs> {
})
}

const url = resolve(matchedEndpoint.url, path)
const url = resolve(matchedEndpoint.url, path || matchedPath)
// TODO: support POST requests with request body
const method = "get"

Expand Down
7 changes: 7 additions & 0 deletions garden-cli/test/data/test-project-b/module-c/garden.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ module:
ports:
- name: http
containerPort: 8080
- name: service-d
endpoints:
- paths: [/path-d]
port: http
ports:
- name: http
containerPort: 8080
build:
dependencies:
- module-b
57 changes: 56 additions & 1 deletion garden-cli/test/src/commands/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ const testProvider: PluginFactory = () => {
url: "http://service-a.test-project-b.local.app.garden:32000",
}],
},
"service-b": {
state: "ready",
endpoints: [{
protocol: "http",
hostname: "service-b.test-project-b.local.app.garden",
paths: ["/"],
url: "http://service-b.test-project-b.local.app.garden:32000",
}],
},
"service-c": {
state: "ready",
},
Expand Down Expand Up @@ -73,6 +82,52 @@ describe("commands.call", () => {

})

it("should default to the path '/' if that is exposed if no path is requested", async () => {
const garden = await Garden.factory(projectRootB, { plugins: [testProvider] })
const ctx = garden.pluginContext
const command = new CallCommand()

nock("http://service-a.test-project-b.local.app.garden:32000")
.get("/path-a")
.reply(200, "bla")

const { result } = await command.action(
ctx,
{
serviceAndPath: "service-a",
},
)

expect(result.url).to.equal("http://service-a.test-project-b.local.app.garden:32000/path-a")
expect(result.serviceName).to.equal("service-a")
expect(result.path).to.equal("/path-a")
expect(result.response.status).to.equal(200)
expect(result.response.data).to.equal("bla")
})

it("should otherwise use the first defined endpoint if no path is requested", async () => {
const garden = await Garden.factory(projectRootB, { plugins: [testProvider] })
const ctx = garden.pluginContext
const command = new CallCommand()

nock("http://service-b.test-project-b.local.app.garden:32000")
.get("/")
.reply(200, "bla")

const { result } = await command.action(
ctx,
{
serviceAndPath: "service-b",
},
)

expect(result.url).to.equal("http://service-b.test-project-b.local.app.garden:32000/")
expect(result.serviceName).to.equal("service-b")
expect(result.path).to.equal("/")
expect(result.response.status).to.equal(200)
expect(result.response.data).to.equal("bla")
})

it("should error if service isn't running", async () => {
const garden = await Garden.factory(projectRootB, { plugins: [testProvider] })
const ctx = garden.pluginContext
Expand All @@ -82,7 +137,7 @@ describe("commands.call", () => {
await command.action(
ctx,
{
serviceAndPath: "service-b/path-b",
serviceAndPath: "service-d/path-d",
},
)
} catch (err) {
Expand Down
1 change: 1 addition & 0 deletions garden-cli/test/src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ describe("DeployCommand", () => {
"deploy.service-a": { version: "1", state: "ready" },
"deploy.service-b": { version: "1", state: "ready" },
"deploy.service-c": { version: "1", state: "ready" },
"deploy.service-d": { version: "1", state: "ready" },
})
})

Expand Down

0 comments on commit b5d4972

Please sign in to comment.