{targetState ? (
) : (
@@ -111,9 +111,14 @@ const NodeContainersList = (props: NodeContainersListProps) => {
/>
{container.state && (
-
-
-
+ <>
+
+
+
+
+
+
+ >
)}
{
+ const { t } = useTranslation('common')
+ const routes = useTeamRoutes()
+ const [viewMode, setViewMode] = useState('table')
+
+ const pageLink: BreadcrumbLink = {
+ name: t('nodes'),
+ url: routes.node.list(),
+ }
+
+ const sublinks: BreadcrumbLink[] = [
+ {
+ name: node.name,
+ url: `${routes.node.details(node.id)}`,
+ },
+ {
+ name: t('inspect'),
+ url: `${routes.node.containerInspect(node.id, { prefix, name })}`,
+ },
+ ]
+
+ return (
+
+
+
+ {inspection && }
+
+
+
+
+
+
+ {t('inspectOf', { name: prefix ? `${prefix}-${name}` : name })}
+
+
+
+ {inspection &&
+ (viewMode === 'table' ? (
+
+ ) : (
+
+ ))}
+
+
+ )
+}
+
+export default NodeContainerInspectPage
+
+const getPageServerSideProps = async (context: NextPageContext) => {
+ const routes = TeamRoutes.fromContext(context)
+
+ const nodeId = context.query.nodeId as string
+ const prefix = context.query.prefix as string
+ const name = context.query.name as string
+
+ const node = await getCruxFromContext(context, routes.node.api.details(nodeId))
+ const inspectApiUrl = `${routes.node.api.details(nodeId)}/${prefix ? `${prefix}/` : ''}containers/${name}/inspect`
+ const res = await getCruxFromContext(context, inspectApiUrl)
+ const inspection = JSON.parse(res.inspection)
+
+ return {
+ props: {
+ node,
+ prefix: prefix ?? null,
+ name: name ?? null,
+ inspection,
+ },
+ }
+}
+
+export const getServerSideProps = withContextAuthorization(getPageServerSideProps)
diff --git a/web/crux-ui/src/pages/[teamSlug]/nodes/[nodeId]/log.tsx b/web/crux-ui/src/pages/[teamSlug]/nodes/[nodeId]/log.tsx
index 0b26f2895..2fdb5342a 100644
--- a/web/crux-ui/src/pages/[teamSlug]/nodes/[nodeId]/log.tsx
+++ b/web/crux-ui/src/pages/[teamSlug]/nodes/[nodeId]/log.tsx
@@ -74,7 +74,7 @@ const NodeContainerLogPage = (props: InstanceLogPageProps) => {
- {t('log')}
+ {t('logOf', { name: prefix ? `${prefix}-${name}` : name })}
diff --git a/web/crux-ui/src/routes.ts b/web/crux-ui/src/routes.ts
index b6a9a5684..934725038 100644
--- a/web/crux-ui/src/routes.ts
+++ b/web/crux-ui/src/routes.ts
@@ -253,6 +253,12 @@ class NodeRoutes {
...params,
anchor: null,
})
+
+ containerInspect = (id: string, params: ContainerLogParams) =>
+ appendUrlParams(`${this.details(id)}/inspect`, {
+ ...params,
+ anchor: null,
+ })
}
class RegistryApi {
diff --git a/web/crux-ui/tailwind.config.js b/web/crux-ui/tailwind.config.js
index 204bb6805..a1142e778 100644
--- a/web/crux-ui/tailwind.config.js
+++ b/web/crux-ui/tailwind.config.js
@@ -30,6 +30,7 @@ module.exports = {
light: '#7783a3',
'medium-eased': '#343d55',
medium: '#283046',
+ 'dark-eased': '#192034',
dark: '#161d31',
'error-red': '#ea5455',
'warning-orange': '#ff9f43',
diff --git a/web/crux/proto/agent.proto b/web/crux/proto/agent.proto
index 4be39cace..2e4c16c98 100644
--- a/web/crux/proto/agent.proto
+++ b/web/crux/proto/agent.proto
@@ -30,6 +30,7 @@ service Agent {
rpc AbortUpdate(AgentAbortUpdate) returns (common.Empty);
rpc DeleteContainers(common.DeleteContainersRequest) returns (common.Empty);
rpc ContainerLog(stream common.ContainerLogMessage) returns (common.Empty);
+ rpc ContainerInspect(common.ContainerInspectMessage) returns (common.Empty);
rpc TokenReplaced(common.Empty) returns (common.Empty);
}
@@ -57,6 +58,7 @@ message AgentCommand {
common.DeleteContainersRequest deleteContainers = 9;
ContainerLogRequest containerLog = 10;
ReplaceTokenRequest replaceToken = 11;
+ ContainerInspectRequest containerInspect = 12;
}
}
@@ -272,6 +274,14 @@ message ContainerLogRequest {
uint32 tail = 3;
}
+/*
+ * Container inspect
+ *
+ */
+message ContainerInspectRequest {
+ common.ContainerIdentifier container = 1;
+}
+
/*
* Connection close
*
diff --git a/web/crux/proto/common.proto b/web/crux/proto/common.proto
index 70345e76a..9fc5b1e2b 100644
--- a/web/crux/proto/common.proto
+++ b/web/crux/proto/common.proto
@@ -77,6 +77,12 @@ message ContainerLogMessage {
string log = 100;
}
+message ContainerInspectMessage {
+ string prefix = 1;
+ string name = 2;
+ string inspection = 3;
+}
+
enum NetworkMode {
NETWORK_MODE_UNSPECIFIED = 0;
BRIDGE = 1;
diff --git a/web/crux/src/app/agent/agent.grpc.controller.ts b/web/crux/src/app/agent/agent.grpc.controller.ts
old mode 100644
new mode 100755
index 323f43981..51b94ea41
--- a/web/crux/src/app/agent/agent.grpc.controller.ts
+++ b/web/crux/src/app/agent/agent.grpc.controller.ts
@@ -10,6 +10,7 @@ import {
AgentController as GrpcAgentController,
} from 'src/grpc/protobuf/proto/agent'
import {
+ ContainerInspectMessage,
ContainerLogMessage,
ContainerStateListMessage,
DeleteContainersRequest,
@@ -58,6 +59,10 @@ export default class AgentController implements GrpcAgentController {
return this.service.handleContainerLog(call.connection, request)
}
+ containerInspect(request: ContainerInspectMessage, _: Metadata, call: NodeGrpcCall): Observable {
+ return this.service.handleContainerInspect(call.connection, request)
+ }
+
async tokenReplaced(_: Empty, __: Metadata, call: NodeGrpcCall): Promise {
return await this.service.tokenReplaced(call.connection)
}
diff --git a/web/crux/src/app/agent/agent.service.ts b/web/crux/src/app/agent/agent.service.ts
old mode 100644
new mode 100755
index da92d95fe..2a5c5de19
--- a/web/crux/src/app/agent/agent.service.ts
+++ b/web/crux/src/app/agent/agent.service.ts
@@ -28,6 +28,7 @@ import { CruxNotFoundException } from 'src/exception/crux-exception'
import { AgentAbortUpdate, AgentCommand, AgentInfo, CloseReason } from 'src/grpc/protobuf/proto/agent'
import {
ContainerIdentifier,
+ ContainerInspectMessage,
ContainerLogMessage,
ContainerStateListMessage,
DeleteContainersRequest,
@@ -353,6 +354,14 @@ export default class AgentService {
)
}
+ handleContainerInspect(connection: GrpcNodeConnection, request: ContainerInspectMessage): Observable {
+ const agent = this.getByIdOrThrow(connection.nodeId)
+
+ agent.onContainerInspect(request)
+
+ return of(Empty)
+ }
+
async tokenReplaced(connection: GrpcNodeConnection): Promise {
const agent = this.getByIdOrThrow(connection.nodeId)
diff --git a/web/crux/src/app/node/node.dto.ts b/web/crux/src/app/node/node.dto.ts
old mode 100644
new mode 100755
index 9b0ccfd85..fac1eab7a
--- a/web/crux/src/app/node/node.dto.ts
+++ b/web/crux/src/app/node/node.dto.ts
@@ -238,3 +238,8 @@ export class NodeAuditLogListDto extends PaginatedList {
total: number
}
+
+export class ContainerInspectionDto {
+ @IsString()
+ inspection: string
+}
diff --git a/web/crux/src/app/node/node.global-container.http.controller.ts b/web/crux/src/app/node/node.global-container.http.controller.ts
index c3f3f6994..8a4036197 100644
--- a/web/crux/src/app/node/node.global-container.http.controller.ts
+++ b/web/crux/src/app/node/node.global-container.http.controller.ts
@@ -22,7 +22,7 @@ import {
ROUTE_NODE_ID,
ROUTE_TEAM_SLUG,
} from './node.const'
-import { ContainerDto } from './node.dto'
+import { ContainerDto, ContainerInspectionDto } from './node.dto'
import NodeService from './node.service'
@Controller(`${ROUTE_TEAM_SLUG}/${ROUTE_NODES}/${ROUTE_NODE_ID}/${ROUTE_CONTAINERS}`)
@@ -99,4 +99,18 @@ export default class NodeGlobalContainerHttpController {
deleteContainer(@NodeId() nodeId: string, @Name() name: string): Observable {
return from(this.service.deleteContainer(nodeId, GLOBAL_PREFIX, name)).pipe(mergeAll())
}
+
+ @Get(`${ROUTE_NAME}/inspect`)
+ @HttpCode(HttpStatus.OK)
+ @ApiOperation({
+ description: 'Request must include `nodeId`, and the `name` of the container.',
+ summary: 'Inspect a specific container on a node.',
+ })
+ @ApiOkResponse({ type: ContainerInspectionDto, description: 'Container inspection.' })
+ @ApiBadRequestResponse({ description: 'Bad request for container inspection.' })
+ @ApiForbiddenResponse({ description: 'Unauthorized request for container inspection.' })
+ @UuidParams(PARAM_NODE_ID)
+ async inspectContainer(@NodeId() nodeId: string, @Name() name: string): Promise {
+ return await this.service.inspectContainer(nodeId, GLOBAL_PREFIX, name)
+ }
}
diff --git a/web/crux/src/app/node/node.mapper.ts b/web/crux/src/app/node/node.mapper.ts
index cddd14ba7..1bb9f7da0 100644
--- a/web/crux/src/app/node/node.mapper.ts
+++ b/web/crux/src/app/node/node.mapper.ts
@@ -6,6 +6,7 @@ import { ContainerState } from 'src/domain/container'
import { NodeWithToken } from 'src/domain/node'
import { fromTimestamp } from 'src/domain/utils'
import {
+ ContainerInspectMessage,
ContainerOperation,
ContainerStateItem,
ContainerStateListMessage,
@@ -18,6 +19,7 @@ import {
BasicNodeDto,
BasicNodeWithStatus,
ContainerDto,
+ ContainerInspectionDto,
ContainerOperationDto,
NodeConnectionStatus,
NodeDetailsDto,
@@ -138,6 +140,12 @@ export default class NodeMapper {
return ContainerOperation.UNRECOGNIZED
}
}
+
+ containerInspectionMessageToDto(it: ContainerInspectMessage): ContainerInspectionDto {
+ return {
+ inspection: it.inspection,
+ }
+ }
}
type NodeDetails = NodeWithToken & {
diff --git a/web/crux/src/app/node/node.prefix-container.http.controller.ts b/web/crux/src/app/node/node.prefix-container.http.controller.ts
old mode 100644
new mode 100755
index b438050fc..8287545b9
--- a/web/crux/src/app/node/node.prefix-container.http.controller.ts
+++ b/web/crux/src/app/node/node.prefix-container.http.controller.ts
@@ -1,9 +1,10 @@
-import { Controller, Delete, HttpCode, HttpStatus, Post, UseGuards } from '@nestjs/common'
+import { Controller, Delete, Get, HttpCode, HttpStatus, Post, UseGuards } from '@nestjs/common'
import {
ApiBadRequestResponse,
ApiForbiddenResponse,
ApiNoContentResponse,
ApiNotFoundResponse,
+ ApiOkResponse,
ApiOperation,
ApiTags,
} from '@nestjs/swagger'
@@ -22,6 +23,7 @@ import {
ROUTE_PREFIX,
ROUTE_TEAM_SLUG,
} from './node.const'
+import { ContainerInspectionDto } from './node.dto'
import NodeService from './node.service'
@Controller(`${ROUTE_TEAM_SLUG}/${ROUTE_NODES}/${ROUTE_NODE_ID}/${ROUTE_PREFIX}/${ROUTE_CONTAINERS}`)
@@ -33,7 +35,7 @@ export default class NodePrefixContainerHttpController {
@Post(`${ROUTE_NAME}/start`)
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({
- description: 'Request must include `nodeId`, `prefix`, and `name`.',
+ description: 'Request must include `nodeId`, `prefix`, and the `name` of the container.',
summary: 'Start a container deployed with dyrector.io on a node.',
})
@ApiNoContentResponse({ description: 'Container started.' })
@@ -47,7 +49,7 @@ export default class NodePrefixContainerHttpController {
@Post(`${ROUTE_NAME}/stop`)
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({
- description: 'Request must include `nodeId`, `prefix`, and `name`.',
+ description: 'Request must include `nodeId`, `prefix`, and the `name` of the container.',
summary: 'Stop a container deployed with dyrector.io on a node.',
})
@ApiNoContentResponse({ description: 'Container stopped.' })
@@ -61,7 +63,7 @@ export default class NodePrefixContainerHttpController {
@Post(`${ROUTE_NAME}/restart`)
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({
- description: 'Request must include `nodeId`, `prefix`, and `name`.',
+ description: 'Request must include `nodeId`, `prefix`, and the `name` of the container.',
summary: 'Restart a container deployed with dyrector.io on a node.',
})
@ApiNoContentResponse({ description: 'Container restarted.' })
@@ -89,7 +91,7 @@ export default class NodePrefixContainerHttpController {
@Delete(`${ROUTE_NAME}`)
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({
- description: 'Request must include `nodeId`, `prefix`, and `name`.',
+ description: 'Request must include `nodeId`, `prefix`, and the `name` of the container.',
summary: 'Delete a container deployed with dyrector.io, with the specified prefix and name on a node.',
})
@ApiNoContentResponse({ description: 'Container deleted.' })
@@ -99,4 +101,22 @@ export default class NodePrefixContainerHttpController {
deleteContainer(@NodeId() nodeId: string, @Prefix() prefix: string, @Name() name: string): Observable {
return from(this.service.deleteContainer(nodeId, prefix, name)).pipe(mergeAll())
}
+
+ @Get(`${ROUTE_NAME}/inspect`)
+ @HttpCode(HttpStatus.OK)
+ @ApiOperation({
+ description: 'Request must include `nodeId`, `prefix`, and the `name` of the container.',
+ summary: 'Inspect a container with the specified prefix and name on a node.',
+ })
+ @ApiOkResponse({ type: ContainerInspectionDto, description: 'Container inspection.' })
+ @ApiBadRequestResponse({ description: 'Bad request for container inspection.' })
+ @ApiForbiddenResponse({ description: 'Unauthorized request for container inspection.' })
+ @UuidParams(PARAM_NODE_ID)
+ async inspectContainer(
+ @NodeId() nodeId: string,
+ @Prefix() prefix: string,
+ @Name() name: string,
+ ): Promise {
+ return await this.service.inspectContainer(nodeId, prefix, name)
+ }
}
diff --git a/web/crux/src/app/node/node.service.ts b/web/crux/src/app/node/node.service.ts
index a16276a60..ffb772bb7 100644
--- a/web/crux/src/app/node/node.service.ts
+++ b/web/crux/src/app/node/node.service.ts
@@ -1,7 +1,18 @@
import { Injectable, Logger } from '@nestjs/common'
import { Identity } from '@ory/kratos-client'
import { Prisma } from '@prisma/client'
-import { EmptyError, Observable, filter, firstValueFrom, map, mergeAll, mergeWith, of, timeout } from 'rxjs'
+import {
+ EmptyError,
+ Observable,
+ filter,
+ firstValueFrom,
+ lastValueFrom,
+ map,
+ mergeAll,
+ mergeWith,
+ of,
+ timeout,
+} from 'rxjs'
import { Agent, AgentConnectionMessage } from 'src/domain/agent'
import { BaseMessage } from 'src/domain/notification-templates'
import {
@@ -18,6 +29,7 @@ import AgentService from '../agent/agent.service'
import TeamRepository from '../team/team.repository'
import {
ContainerDto,
+ ContainerInspectionDto,
CreateNodeDto,
NodeAuditLogListDto,
NodeAuditLogQueryDto,
@@ -408,6 +420,14 @@ export default class NodeService {
}
}
+ async inspectContainer(nodeId: string, prefix: string, name: string): Promise {
+ const agent = this.agentService.getByIdOrThrow(nodeId)
+ const watcher = agent.getContainerInspection(prefix, name)
+ const inspectionMessage = await lastValueFrom(watcher)
+
+ return this.mapper.containerInspectionMessageToDto(inspectionMessage)
+ }
+
private static snakeCaseToCamelCase(snake: string): string {
return snake.toLocaleLowerCase().replace(/([-_][a-z])/g, it => it.replace('_', '').toLocaleUpperCase())
}
diff --git a/web/crux/src/domain/agent.spec.ts b/web/crux/src/domain/agent.spec.ts
index 693de9321..6b14db228 100644
--- a/web/crux/src/domain/agent.spec.ts
+++ b/web/crux/src/domain/agent.spec.ts
@@ -11,7 +11,7 @@ import {
DeploymentStatusMessage,
Empty,
} from 'src/grpc/protobuf/proto/common'
-import { DEFAULT_CONTAINER_LOG_TAIL } from 'src/shared/const'
+import { DEFAULT_CONTAINER_LOG_TAIL, GET_CONTAINER_SECRETS_TIMEOUT_MILLIS } from 'src/shared/const'
import { Agent, AgentConnectionMessage } from './agent'
import { generateAgentToken } from './agent-token'
import AgentUpdate from './agent-update'
@@ -325,7 +325,7 @@ describe('agent', () => {
await expect(secrets).rejects.toThrow()
},
- Agent.SECRET_TIMEOUT * 2,
+ GET_CONTAINER_SECRETS_TIMEOUT_MILLIS * 2,
)
// Default timeout is 5sec, but getContainerSecrets also uses a 5sec timeout
// so we need to increase the default timeout to test the secret timeout
diff --git a/web/crux/src/domain/agent.ts b/web/crux/src/domain/agent.ts
old mode 100644
new mode 100755
index a911d57bd..365588be6
--- a/web/crux/src/domain/agent.ts
+++ b/web/crux/src/domain/agent.ts
@@ -11,12 +11,18 @@ import { AgentCommand, AgentInfo, CloseReason } from 'src/grpc/protobuf/proto/ag
import {
ContainerCommandRequest,
ContainerIdentifier,
+ ContainerInspectMessage,
DeleteContainersRequest,
DeploymentStatusMessage,
Empty,
ListSecretsResponse,
} from 'src/grpc/protobuf/proto/common'
-import { CONTAINER_DELETE_TIMEOUT, DEFAULT_CONTAINER_LOG_TAIL } from 'src/shared/const'
+import {
+ CONTAINER_DELETE_TIMEOUT_MILLIS,
+ DEFAULT_CONTAINER_LOG_TAIL,
+ GET_CONTAINER_INSPECTION_TIMEOUT_MILLIS,
+ GET_CONTAINER_SECRETS_TIMEOUT_MILLIS,
+} from 'src/shared/const'
import GrpcNodeConnection from 'src/shared/grpc-node-connection'
import { AgentToken } from './agent-token'
import AgentUpdate, { AgentUpdateOptions, AgentUpdateResult } from './agent-update'
@@ -39,8 +45,6 @@ export type AgentTokenReplacement = {
}
export class Agent {
- public static SECRET_TIMEOUT = 5000
-
private readonly commandChannel = new BufferedSubject()
private deployments: Map = new Map()
@@ -49,6 +53,8 @@ export class Agent {
private secretsWatchers: Map> = new Map()
+ private inspectionWatchers: Map> = new Map()
+
private deleteContainersRequests: Map> = new Map()
private logStreams: Map = new Map()
@@ -222,7 +228,7 @@ export class Agent {
} as AgentCommand)
return result.pipe(
- timeout(CONTAINER_DELETE_TIMEOUT),
+ timeout(CONTAINER_DELETE_TIMEOUT_MILLIS),
catchError(err => {
if (err instanceof TimeoutError) {
result.complete()
@@ -253,6 +259,7 @@ export class Agent {
this.deployments.forEach(it => it.onDisconnected())
this.statusWatchers.forEach(it => it.stop())
this.secretsWatchers.forEach(it => it.complete())
+ this.inspectionWatchers.forEach(it => it.complete())
this.logStreams.forEach(it => it.stop())
this.commandChannel.complete()
@@ -337,7 +344,7 @@ export class Agent {
this.secretsWatchers.delete(key)
}),
timeout({
- each: Agent.SECRET_TIMEOUT,
+ each: GET_CONTAINER_SECRETS_TIMEOUT_MILLIS,
with: () => {
this.secretsWatchers.delete(key)
@@ -366,6 +373,63 @@ export class Agent {
this.secretsWatchers.delete(key)
}
+ getContainerInspection(prefix: string, name: string): Observable {
+ this.throwIfCommandsAreDisabled()
+
+ const key = Agent.containerPrefixNameOf({
+ prefix,
+ name,
+ })
+
+ let watcher = this.inspectionWatchers.get(key)
+ if (!watcher) {
+ watcher = new Subject()
+ this.inspectionWatchers.set(key, watcher)
+
+ this.commandChannel.next({
+ containerInspect: {
+ container: {
+ prefix,
+ name,
+ },
+ },
+ } as AgentCommand)
+ }
+
+ return watcher.pipe(
+ finalize(() => {
+ this.inspectionWatchers.delete(key)
+ }),
+ timeout({
+ each: GET_CONTAINER_INSPECTION_TIMEOUT_MILLIS,
+ with: () => {
+ this.inspectionWatchers.delete(key)
+
+ return throwError(
+ () =>
+ new CruxInternalServerErrorException({
+ message: 'Agent container inspection timed out.',
+ }),
+ )
+ },
+ }),
+ )
+ }
+
+ onContainerInspect(res: ContainerInspectMessage) {
+ const key = Agent.containerPrefixNameOf(res)
+
+ const watcher = this.inspectionWatchers.get(key)
+ if (!watcher) {
+ return
+ }
+
+ watcher.next(res)
+ watcher.complete()
+
+ this.inspectionWatchers.delete(key)
+ }
+
startUpdate(tag: string, options: AgentUpdateOptions) {
if (this.deployments.size > 0) {
throw new CruxPreconditionFailedException({
diff --git a/web/crux/src/grpc/protobuf/proto/agent.ts b/web/crux/src/grpc/protobuf/proto/agent.ts
index 044a6216c..05f0c2885 100644
--- a/web/crux/src/grpc/protobuf/proto/agent.ts
+++ b/web/crux/src/grpc/protobuf/proto/agent.ts
@@ -6,6 +6,7 @@ import {
ConfigContainer,
ContainerCommandRequest,
ContainerIdentifier,
+ ContainerInspectMessage,
ContainerLogMessage,
ContainerStateListMessage,
DeleteContainersRequest,
@@ -114,6 +115,7 @@ export interface AgentCommand {
deleteContainers?: DeleteContainersRequest | undefined
containerLog?: ContainerLogRequest | undefined
replaceToken?: ReplaceTokenRequest | undefined
+ containerInspect?: ContainerInspectRequest | undefined
}
/**
@@ -368,6 +370,11 @@ export interface ContainerLogRequest {
tail: number
}
+/** Container inspect */
+export interface ContainerInspectRequest {
+ container: ContainerIdentifier | undefined
+}
+
export interface CloseConnectionRequest {
reason: CloseReason
}
@@ -422,6 +429,9 @@ export const AgentCommand = {
: undefined,
containerLog: isSet(object.containerLog) ? ContainerLogRequest.fromJSON(object.containerLog) : undefined,
replaceToken: isSet(object.replaceToken) ? ReplaceTokenRequest.fromJSON(object.replaceToken) : undefined,
+ containerInspect: isSet(object.containerInspect)
+ ? ContainerInspectRequest.fromJSON(object.containerInspect)
+ : undefined,
}
},
@@ -455,6 +465,10 @@ export const AgentCommand = {
(obj.containerLog = message.containerLog ? ContainerLogRequest.toJSON(message.containerLog) : undefined)
message.replaceToken !== undefined &&
(obj.replaceToken = message.replaceToken ? ReplaceTokenRequest.toJSON(message.replaceToken) : undefined)
+ message.containerInspect !== undefined &&
+ (obj.containerInspect = message.containerInspect
+ ? ContainerInspectRequest.toJSON(message.containerInspect)
+ : undefined)
return obj
},
}
@@ -1441,6 +1455,23 @@ export const ContainerLogRequest = {
},
}
+function createBaseContainerInspectRequest(): ContainerInspectRequest {
+ return { container: undefined }
+}
+
+export const ContainerInspectRequest = {
+ fromJSON(object: any): ContainerInspectRequest {
+ return { container: isSet(object.container) ? ContainerIdentifier.fromJSON(object.container) : undefined }
+ },
+
+ toJSON(message: ContainerInspectRequest): unknown {
+ const obj: any = {}
+ message.container !== undefined &&
+ (obj.container = message.container ? ContainerIdentifier.toJSON(message.container) : undefined)
+ return obj
+ },
+}
+
function createBaseCloseConnectionRequest(): CloseConnectionRequest {
return { reason: 0 }
}
@@ -1482,6 +1513,8 @@ export interface AgentClient {
containerLog(request: Observable, metadata: Metadata, ...rest: any): Observable
+ containerInspect(request: ContainerInspectMessage, metadata: Metadata, ...rest: any): Observable
+
tokenReplaced(request: Empty, metadata: Metadata, ...rest: any): Observable
}
@@ -1526,12 +1559,25 @@ export interface AgentController {
...rest: any
): Promise | Observable | Empty
+ containerInspect(
+ request: ContainerInspectMessage,
+ metadata: Metadata,
+ ...rest: any
+ ): Promise | Observable | Empty
+
tokenReplaced(request: Empty, metadata: Metadata, ...rest: any): Promise | Observable | Empty
}
export function AgentControllerMethods() {
return function (constructor: Function) {
- const grpcMethods: string[] = ['connect', 'secretList', 'abortUpdate', 'deleteContainers', 'tokenReplaced']
+ const grpcMethods: string[] = [
+ 'connect',
+ 'secretList',
+ 'abortUpdate',
+ 'deleteContainers',
+ 'containerInspect',
+ 'tokenReplaced',
+ ]
for (const method of grpcMethods) {
const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method)
GrpcMethod('Agent', method)(constructor.prototype[method], method, descriptor)
diff --git a/web/crux/src/grpc/protobuf/proto/common.ts b/web/crux/src/grpc/protobuf/proto/common.ts
index fdf3eedc3..7bf7f2efc 100644
--- a/web/crux/src/grpc/protobuf/proto/common.ts
+++ b/web/crux/src/grpc/protobuf/proto/common.ts
@@ -564,6 +564,12 @@ export interface ContainerLogMessage {
log: string
}
+export interface ContainerInspectMessage {
+ prefix: string
+ name: string
+ inspection: string
+}
+
export interface Routing {
domain?: string | undefined
path?: string | undefined
@@ -835,6 +841,28 @@ export const ContainerLogMessage = {
},
}
+function createBaseContainerInspectMessage(): ContainerInspectMessage {
+ return { prefix: '', name: '', inspection: '' }
+}
+
+export const ContainerInspectMessage = {
+ fromJSON(object: any): ContainerInspectMessage {
+ return {
+ prefix: isSet(object.prefix) ? String(object.prefix) : '',
+ name: isSet(object.name) ? String(object.name) : '',
+ inspection: isSet(object.inspection) ? String(object.inspection) : '',
+ }
+ },
+
+ toJSON(message: ContainerInspectMessage): unknown {
+ const obj: any = {}
+ message.prefix !== undefined && (obj.prefix = message.prefix)
+ message.name !== undefined && (obj.name = message.name)
+ message.inspection !== undefined && (obj.inspection = message.inspection)
+ return obj
+ },
+}
+
function createBaseRouting(): Routing {
return {}
}
diff --git a/web/crux/src/shared/const.ts b/web/crux/src/shared/const.ts
index 4d59edb67..7ae819958 100644
--- a/web/crux/src/shared/const.ts
+++ b/web/crux/src/shared/const.ts
@@ -14,7 +14,9 @@ export const VERSIONLESS_PROJECT_VERSION_NAME = 'rolling'
const DAY_IN_MILLIS = 24 * 60 * 60 * 1000
export const TEAM_INVITATION_EXPIRATION = 7 * DAY_IN_MILLIS
export const JWT_EXPIRATION_MILLIS = 10 * 60 * 1000 // 10 minutes
-export const CONTAINER_DELETE_TIMEOUT = 1000 // millis
+export const CONTAINER_DELETE_TIMEOUT_MILLIS = 1000
+export const GET_CONTAINER_SECRETS_TIMEOUT_MILLIS = 5000
+export const GET_CONTAINER_INSPECTION_TIMEOUT_MILLIS = 5000
export const DEFAULT_CONTAINER_LOG_TAIL = 40