Skip to content
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

fix: handle missing services gracefully in logs command #343

Merged
merged 1 commit into from
Oct 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions garden-service/src/commands/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,17 @@ export class LogsCommand extends Command<Args, Opts> {
}
})

// NOTE: This will work differently when we have Elasticsearch set up for logging, but is
// quite servicable for now.
await Bluebird.map(services, async (service: Service<any>) => {
await garden.actions.getServiceLogs({ service, stream, tail })
const status = await garden.actions.getServiceStatus({ service })
if (status.state === "ready" || status.state === "outdated") {
await garden.actions.getServiceLogs({ service, stream, tail })
} else {
await stream.write({
serviceName: service.name,
timestamp: new Date(),
msg: chalk.yellow(`<Service not running (state: ${status.state}). Please deploy the service and try again.>`),
})
}
})

return { result }
Expand Down
2 changes: 0 additions & 2 deletions garden-service/src/plugins/kubernetes/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,6 @@ export async function getServiceLogs(
void stream.write({ serviceName: service.name, timestamp, msg })
})

proc.stderr.pipe(process.stderr)

return new Promise<GetServiceLogsResult>((resolve, reject) => {
proc.on("error", reject)

Expand Down
6 changes: 3 additions & 3 deletions garden-service/src/plugins/kubernetes/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ export async function getContainerServiceStatus(

// FIXME: [objects, matched] and ingresses can be run in parallel
const objects = await createContainerObjects(ctx, service, runtimeContext, enableHotReload)
const matched = await compareDeployedObjects(ctx, objects)
const state = await compareDeployedObjects(ctx, objects)
const ingresses = await getIngresses(service, api)

return {
ingresses,
state: matched ? "ready" : "outdated",
version: matched ? version.versionString : undefined,
state,
version: state === "ready" ? version.versionString : undefined,
}
}

Expand Down
8 changes: 4 additions & 4 deletions garden-service/src/plugins/kubernetes/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,10 @@ async function getServiceStatus(

// first check if the installed objects on the cluster match the current code
const objects = await getChartObjects(ctx, service, logEntry)
const matched = await compareDeployedObjects(ctx, objects)
let state = await compareDeployedObjects(ctx, objects)

if (!matched) {
return { state: "outdated" }
if (state !== "ready") {
return { state }
}

// then check if the rollout is complete
Expand All @@ -327,7 +327,7 @@ async function getServiceStatus(
const { ready } = await checkObjectStatus(api, namespace, objects)

// TODO: set state to "unhealthy" if any status is "unhealthy"
const state = ready ? "ready" : "deploying"
state = ready ? "ready" : "deploying"

return { state, version: version.versionString }
}
Expand Down
15 changes: 10 additions & 5 deletions garden-service/src/plugins/kubernetes/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,11 +397,14 @@ export async function waitForServices(
/**
* Check if each of the given Kubernetes objects matches what's installed in the cluster
*/
export async function compareDeployedObjects(ctx: PluginContext, objects: KubernetesObject[]): Promise<boolean> {
export async function compareDeployedObjects(ctx: PluginContext, objects: KubernetesObject[]): Promise<ServiceState> {
const existingObjects = await Bluebird.map(objects, obj => getDeployedObject(ctx, ctx.provider, obj))
let missing = true

for (let [obj, existingSpec] of zip(objects, existingObjects)) {
if (existingSpec && obj) {
missing = false

// the API version may implicitly change when deploying
existingSpec.apiVersion = obj.apiVersion

Expand Down Expand Up @@ -436,19 +439,21 @@ export async function compareDeployedObjects(ctx: PluginContext, objects: Kubern
obj = <KubernetesObject>removeNull(obj)
}

if (!existingSpec || !isSubset(existingSpec, obj)) {
if (existingSpec && !isSubset(existingSpec, obj)) {
// console.log(JSON.stringify(obj, null, 4))
// console.log(JSON.stringify(existingSpec, null, 4))
// console.log("----------------------------------------------------")
// throw new Error("bla")
return false
return "outdated"
}
}

return true
return missing ? "missing" : "ready"
}

async function getDeployedObject(ctx: PluginContext, provider: KubernetesProvider, obj: KubernetesObject) {
async function getDeployedObject(
ctx: PluginContext, provider: KubernetesProvider, obj: KubernetesObject,
): Promise<KubernetesObject | null> {
const api = new KubeApi(provider)
const namespace = obj.metadata.namespace || await getAppNamespace(ctx, provider)

Expand Down