interface DetailsAttributeDataProps {
label: string;
classLabel?: string;
- value?: string | number;
+ value?: React.ReactNode;
classValue?: string;
lowercaseValue?: boolean;
link?: string;
// SPDX-License-Identifier: AGPL-3.0
import { Resource, ResourceKind } from "./resource";
+import { MountType } from "~/models/mount-types";
+import { RuntimeConstraints } from './runtime-constraints';
+import { SchedulingParameters } from './scheduling-parameters';
export enum ContainerRequestState {
UNCOMMITTED = "Uncommitted",
description: string;
properties: any;
state: ContainerRequestState;
- requestingContainerUuid: string;
- containerUuid: string;
+ requestingContainerUuid: string | null;
+ containerUuid: string | null;
containerCountMax: number;
- mounts: any;
- runtimeConstraints: any;
- schedulingParameters: any;
+ mounts: MountType[];
+ runtimeConstraints: RuntimeConstraints;
+ schedulingParameters: SchedulingParameters;
containerImage: string;
environment: any;
cwd: string;
outputPath: string;
outputName: string;
outputTtl: number;
- priority: number;
+ priority: number | null;
expiresAt: string;
useExisting: boolean;
- logUuid: string;
- outputUuid: string;
+ logUuid: string | null;
+ outputUuid: string | null;
filters: string;
}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Resource, ResourceKind } from "./resource";
+import { MountType } from '~/models/mount-types';
+import { RuntimeConstraints } from "~/models/runtime-constraints";
+import { SchedulingParameters } from './scheduling-parameters';
+
+export enum ContainerState {
+ QUEUED = 'Queued',
+ LOCKED = 'Locked',
+ RUNNING = 'Running',
+ COMPLETE = 'Complete',
+ CANCELLED = 'Cancelled',
+}
+
+export interface ContainerResource extends Resource {
+ kind: ResourceKind.CONTAINER;
+ state: string;
+ startedAt: string | null;
+ finishedAt: string | null;
+ log: string | null;
+ environment: {};
+ cwd: string;
+ command: string[];
+ outputPath: string;
+ mounts: MountType[];
+ runtimeConstraints: RuntimeConstraints;
+ schedulingParameters: SchedulingParameters;
+ output: string | null;
+ containerImage: string;
+ progress: number;
+ priority: number;
+ exitCode: number | null;
+ authUuid: string | null;
+ lockedByUuid: string | null;
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export enum MountKind {
+ COLLECTION = 'collection',
+ GIT_TREE = 'git_tree',
+ TEMPORARY_DIRECTORY = 'tmp',
+ KEEP = 'keep',
+ MOUNTED_FILE = 'file',
+ JSON = 'JSON'
+}
+
+export type MountType =
+ CollectionMount |
+ GitTreeMount |
+ TemporaryDirectoryMount |
+ KeepMount |
+ JSONMount;
+
+export interface CollectionMount {
+ kind: MountKind.COLLECTION;
+ uuid?: string;
+ portableDataHash?: string;
+ path?: string;
+ writable?: boolean;
+}
+
+export interface GitTreeMount {
+ kind: MountKind.GIT_TREE;
+ uuid: string;
+ commit: string;
+ path?: string;
+}
+
+export enum TemporaryDirectoryDeviceType {
+ RAM = 'ram',
+ SSD = 'ssd',
+ DISK = 'disk',
+ NETWORK = 'network',
+}
+
+export interface TemporaryDirectoryMount {
+ kind: MountKind.TEMPORARY_DIRECTORY;
+ capacity: number;
+ deviceType: TemporaryDirectoryDeviceType;
+}
+
+export interface KeepMount {
+ kind: MountKind.KEEP;
+}
+
+export interface JSONMount {
+ kind: MountKind.JSON;
+ content: string;
+}
export enum ResourceKind {
COLLECTION = "arvados#collection",
+ CONTAINER = "arvados#container",
CONTAINER_REQUEST = "arvados#containerRequest",
GROUP = "arvados#group",
PROCESS = "arvados#containerRequest",
PROJECT = "arvados#group",
- WORKFLOW = "arvados#workflow",
USER = "arvados#user",
+ WORKFLOW = "arvados#workflow",
}
export enum ResourceObjectType {
- USER = 'tpzed',
+ COLLECTION = '4zz18',
+ CONTAINER = 'dz642',
+ CONTAINER_REQUEST = 'xvhdp',
GROUP = 'j7d0g',
- COLLECTION = '4zz18'
+ USER = 'tpzed',
}
export const RESOURCE_UUID_PATTERN = '.{5}-.{5}-.{15}';
return ResourceKind.GROUP;
case ResourceObjectType.COLLECTION:
return ResourceKind.COLLECTION;
+ case ResourceObjectType.CONTAINER_REQUEST:
+ return ResourceKind.CONTAINER_REQUEST;
+ case ResourceObjectType.CONTAINER:
+ return ResourceKind.CONTAINER;
default:
return undefined;
}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export interface RuntimeConstraints {
+ ram: number;
+ vcpus: number;
+ keepCacheRam: number;
+ API: boolean;
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export interface SchedulingParameters {
+ partitions: string[];
+ preemptible: boolean;
+ maxRunTime: number;
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { CommonResourceService } from "~/common/api/common-resource-service";
+import { AxiosInstance } from "axios";
+import { ContainerRequestResource } from '../../models/container-request';
+
+export class ContainerRequestService extends CommonResourceService<ContainerRequestResource> {
+ constructor(serverApi: AxiosInstance) {
+ super(serverApi, "container_requests");
+ }
+}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { CommonResourceService } from "~/common/api/common-resource-service";
+import { AxiosInstance } from "axios";
+import { ContainerResource } from '../../models/container';
+
+export class ContainerService extends CommonResourceService<ContainerResource> {
+ constructor(serverApi: AxiosInstance) {
+ super(serverApi, "containers");
+ }
+}
import { UserService } from './user-service/user-service';
import { AncestorService } from "~/services/ancestors-service/ancestors-service";
import { ResourceKind } from "~/models/resource";
+import { ContainerRequestService } from './container-request-service/container-request-service';
+import { ContainerService } from './container-service/container-service';
export type ServiceRepository = ReturnType<typeof createServices>;
const webdavClient = new WebDAV();
webdavClient.defaults.baseURL = config.keepWebServiceUrl;
- const authService = new AuthService(apiClient, config.rootUrl);
- const keepService = new KeepService(apiClient);
const groupsService = new GroupsService(apiClient);
- const projectService = new ProjectService(apiClient);
+ const keepService = new KeepService(apiClient);
const linkService = new LinkService(apiClient);
- const favoriteService = new FavoriteService(linkService, groupsService);
- const collectionService = new CollectionService(apiClient, webdavClient, authService);
- const tagService = new TagService(linkService);
- const collectionFilesService = new CollectionFilesService(collectionService);
+ const projectService = new ProjectService(apiClient);
const userService = new UserService(apiClient);
+ const containerRequestService = new ContainerRequestService(apiClient);
+ const containerService = new ContainerService(apiClient);
+
const ancestorsService = new AncestorService(groupsService, userService);
+ const authService = new AuthService(apiClient, config.rootUrl);
+ const collectionService = new CollectionService(apiClient, webdavClient, authService);
+ const collectionFilesService = new CollectionFilesService(collectionService);
+ const favoriteService = new FavoriteService(linkService, groupsService);
+ const tagService = new TagService(linkService);
return {
+ ancestorsService,
apiClient,
- webdavClient,
authService,
- keepService,
+ collectionFilesService,
+ collectionService,
+ containerRequestService,
+ containerService,
+ favoriteService,
groupsService,
- projectService,
+ keepService,
linkService,
- favoriteService,
- collectionService,
+ projectService,
tagService,
- collectionFilesService,
userService,
- ancestorsService,
+ webdavClient,
};
};
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ContainerRequestResource } from '../../models/container-request';
+import { ContainerResource } from '../../models/container';
+import { ResourcesState, getResource } from '~/store/resources/resources';
+import { filterResources } from '../resources/resources';
+import { ResourceKind, Resource } from '~/models/resource';
+
+export interface Process {
+ containerRequest: ContainerRequestResource;
+ container?: ContainerResource;
+}
+
+export const getProcess = (uuid: string) => (resources: ResourcesState): Process | undefined => {
+ const containerRequest = getResource<ContainerRequestResource>(uuid)(resources);
+ if (containerRequest) {
+ if (containerRequest.containerUuid) {
+ const container = getResource<ContainerResource>(containerRequest.containerUuid)(resources);
+ if (container) {
+ return { containerRequest, container };
+ }
+ }
+ return { containerRequest };
+ }
+ return;
+};
+
+export const getSubprocesses = (uuid: string) => (resources: ResourcesState) => {
+ const containerRequests = filterResources(isSubprocess(uuid))(resources) as ContainerRequestResource[];
+ return containerRequests.reduce((subprocesses, { uuid }) => {
+ const process = getProcess(uuid)(resources);
+ return process
+ ? [...subprocesses, process]
+ : subprocesses;
+ }, []);
+};
+
+export const getProcessStatus = (process: Process) =>
+ process.container
+ ? process.container.state
+ : process.containerRequest.state;
+
+const isSubprocess = (uuid: string) => (resource: Resource) =>
+ resource.kind === ResourceKind.CONTAINER_REQUEST
+ && (resource as ContainerRequestResource).requestingContainerUuid === uuid;
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch } from "redux";
+import { RootState } from '~/store/store';
+import { ServiceRepository } from '~/services/services';
+import { updateResources } from '~/store/resources/resources-actions';
+import { FilterBuilder } from '~/common/api/filter-builder';
+import { ContainerRequestResource } from '../../models/container-request';
+
+export const loadProcess = (uuid: string) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const containerRequest = await services.containerRequestService.get(uuid);
+ dispatch<any>(updateResources([containerRequest]));
+ if (containerRequest.containerUuid) {
+ const container = await services.containerService.get(containerRequest.containerUuid);
+ dispatch<any>(updateResources([container]));
+ }
+ };
+
+export const loadSubprocesses = (uuid: string) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const containerRequests = await dispatch<any>(loadContainerRequests(
+ new FilterBuilder().addEqual('requestingContainerUuid', uuid).getFilters()
+ )) as ContainerRequestResource[];
+
+ const containerUuids: string[] = containerRequests.reduce((uuids, { containerUuid }) =>
+ containerUuid
+ ? [...uuids, containerUuid]
+ : uuids, []);
+
+ if (containerUuids.length > 0) {
+ await dispatch<any>(loadContainers(
+ new FilterBuilder().addIn('uuid', containerUuids).getFilters()
+ ));
+ }
+ };
+
+export const loadContainerRequests = (filters: string) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const { items } = await services.containerRequestService.list({ filters });
+ dispatch<any>(updateResources(items));
+ return items;
+ };
+
+export const loadContainers = (filters: string) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const { items } = await services.containerService.list({ filters });
+ dispatch<any>(updateResources(items));
+ return items;
+ };
export const deleteResource = (id: string) =>
(state: ResourcesState) => {
- const newState = {...state};
+ const newState = { ...state };
delete newState[id];
return newState;
};
(state: ResourcesState) =>
Object
.keys(state)
- .map(id => getResource(id)(state))
+ .reduce((resources, id) => {
+ const resource = getResource(id)(state);
+ return resource
+ ? [...resources, resource]
+ : resources;
+ }, [])
.filter(filter);
export const filterResourcesByKind = (kind: ResourceKind) =>
(state: ResourcesState) =>
filterResources(resource => resource.kind === kind)(state);
-
{/* Links but we dont have view */}
<DetailsAttribute label='Outputs' link={this.item.outputPath} value={this.item.outputPath} />
<DetailsAttribute label='UUID' link={this.item.uuid} value={this.item.uuid} />
- <DetailsAttribute label='Container UUID' link={this.item.containerUuid} value={this.item.containerUuid} />
+ <DetailsAttribute label='Container UUID' link={this.item.containerUuid || ''} value={this.item.containerUuid} />
<DetailsAttribute label='Priority' value={this.item.priority} />
<DetailsAttribute label='Runtime Constraints' value={this.item.runtimeConstraints} />