Skip to content

Commit

Permalink
urls: wait for all expected services
Browse files Browse the repository at this point in the history
wait for all expected services to be returned from the CTA query
  • Loading branch information
Roy Razon committed May 9, 2024
1 parent e87e57e commit 869a403
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 16 deletions.
11 changes: 6 additions & 5 deletions packages/cli/src/commands/up.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Args, Flags } from '@oclif/core'
import { buildFlags, parseBuildFlags, tableFlags, text, tunnelServerFlags } from '@preevy/cli-common'
import { editUrl, tunnelNameResolver } from '@preevy/common'
import {
ComposeModel,
Logger,
Expand All @@ -11,13 +13,11 @@ import {
telemetryEmitter,
withSpinner,
} from '@preevy/core'
import { buildFlags, parseBuildFlags, tableFlags, text, tunnelServerFlags } from '@preevy/cli-common'
import { inspect } from 'util'
import { editUrl, tunnelNameResolver } from '@preevy/common'
import MachineCreationDriverCommand from '../machine-creation-driver-command.js'
import { envIdFlags, urlFlags } from '../common-flags.js'
import { filterUrls, printUrls, writeUrlsToFile } from './urls.js'
import MachineCreationDriverCommand from '../machine-creation-driver-command.js'
import { connectToTunnelServerSsh } from '../tunnel-server-client.js'
import { filterUrls, printUrls, writeUrlsToFile } from './urls.js'

const fetchTunnelServerDetails = async ({
log,
Expand Down Expand Up @@ -179,7 +179,7 @@ export default class Up extends MachineCreationDriverCommand<typeof Up> {

const buildSpec = parseBuildFlags(flags)

await commands.up({
const { composeModel } = await commands.up({
connection,
machineStatusCommand,
dockerPlatform,
Expand All @@ -205,6 +205,7 @@ export default class Up extends MachineCreationDriverCommand<typeof Up> {

this.log(`Preview environment ${text.code(envId)} provisioned at: ${text.code(machine.locationDescription)}`)

const expectedServiceNames = Object.keys(composeModel.services ?? {})
const composeTunnelServiceUrl = findComposeTunnelAgentUrl(expectedServiceUrls)
const flatTunnels = await withSpinner(() => commands.urls({
composeTunnelServiceUrl,
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/commands/urls.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import retry from 'p-retry'
import { COMPOSE_TUNNEL_AGENT_SERVICE_NAME } from '@preevy/common'
import { generateBasicAuthCredentials, jwtGenerator } from '../credentials/index.js'
import retry from 'p-retry'
import { queryTunnels } from '../compose-tunnel-agent-client.js'
import { generateBasicAuthCredentials, jwtGenerator } from '../credentials/index.js'
import { FlatTunnel, flattenTunnels } from '../tunneling/index.js'

const tunnelFilter = ({ serviceAndPort, showPreevyService }: {
Expand All @@ -26,6 +26,7 @@ export const urls = async ({
showPreevyService,
composeTunnelServiceUrl,
fetchTimeout,
expectedServiceNames,
}: {
serviceAndPort?: { service: string; port?: number }
tunnelingKey: string | Buffer
Expand All @@ -34,6 +35,7 @@ export const urls = async ({
showPreevyService: boolean
composeTunnelServiceUrl: string
fetchTimeout: number
expectedServiceNames?: string[]
}) => {
const credentials = await generateBasicAuthCredentials(jwtGenerator(tunnelingKey))

Expand All @@ -43,6 +45,7 @@ export const urls = async ({
credentials,
includeAccessCredentials,
fetchTimeout,
expectedServiceNames,
})

return flattenTunnels(tunnels).filter(tunnelFilter({ serviceAndPort, showPreevyService }))
Expand Down
35 changes: 26 additions & 9 deletions packages/core/src/compose-tunnel-agent-client.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import path from 'path'
import { COMPOSE_TUNNEL_AGENT_PORT, COMPOSE_TUNNEL_AGENT_SERVICE_LABELS, COMPOSE_TUNNEL_AGENT_SERVICE_NAME, MachineStatusCommand, ScriptInjection, dateReplacer } from '@preevy/common'
import { mapValues, merge } from 'lodash-es'
import { createRequire } from 'module'
import retry from 'p-retry'
import path from 'path'
import util from 'util'
import { createRequire } from 'module'
import { mapValues, merge } from 'lodash-es'
import { COMPOSE_TUNNEL_AGENT_PORT, COMPOSE_TUNNEL_AGENT_SERVICE_LABELS, COMPOSE_TUNNEL_AGENT_SERVICE_NAME, MachineStatusCommand, ScriptInjection, dateReplacer } from '@preevy/common'
import { ComposeModel, ComposeService, composeModelFilename } from './compose/model.js'
import { TunnelOpts } from './ssh/url.js'
import { Tunnel } from './tunneling/index.js'
import { addScriptInjectionsToServices } from './compose/script-injection.js'
import { withBasicAuthCredentials } from './credentials/index.js'
import { EnvId } from './env-id.js'
import { EnvMetadata, driverMetadataFilename } from './env-metadata.js'
import { REMOTE_DIR_BASE } from './remote-files.js'
import { EnvId } from './env-id.js'
import { addScriptInjectionsToServices } from './compose/script-injection.js'
import { TunnelOpts } from './ssh/url.js'
import { Tunnel } from './tunneling/index.js'

const require = createRequire(import.meta.url)
const COMPOSE_TUNNEL_AGENT_DIR = path.join(path.dirname(require.resolve('@preevy/compose-tunnel-agent')), '..')
Expand Down Expand Up @@ -156,18 +156,31 @@ export const findComposeTunnelAgentUrl = (
return serviceUrl
}

const ensureExpectedServices = (
{ tunnels }: { tunnels: Tunnel[] },
expectedServiceNames: string[]
) => {
const actualServiceNames = new Set(tunnels.map(tunnel => tunnel.service))
const missingServiceNames = expectedServiceNames.filter(name => !actualServiceNames.has(name))
if (missingServiceNames.length) {
throw new Error(`Expected service names ${missingServiceNames.join(', ')} not found in tunnels: ${util.inspect(tunnels)}`)
}
}

export const queryTunnels = async ({
retryOpts = { retries: 0 },
composeTunnelServiceUrl,
credentials,
includeAccessCredentials,
fetchTimeout,
expectedServiceNames,
}: {
composeTunnelServiceUrl: string
credentials: { user: string; password: string }
retryOpts?: retry.Options
includeAccessCredentials: false | 'browser' | 'api'
fetchTimeout: number
expectedServiceNames?: string[]
}) => {
const { tunnels } = await retry(async () => {
const r = await fetch(
Expand All @@ -177,7 +190,11 @@ export const queryTunnels = async ({
if (!r.ok) {
throw new Error(`Failed to connect to docker proxy at ${composeTunnelServiceUrl}: ${r.status}: ${r.statusText}`)
}
return await (r.json() as Promise<{ tunnels: Tunnel[] }>)
const tunnelsObj = await (r.json() as Promise<{ tunnels: Tunnel[] }>)
if (expectedServiceNames) {
ensureExpectedServices(tunnelsObj, expectedServiceNames)
}
return tunnelsObj
}, retryOpts)

return tunnels
Expand Down

0 comments on commit 869a403

Please sign in to comment.