store/cockpitApi: compose status support
Finds the relevant compose, asks for its status and reads the original compose request from disk.
This commit is contained in:
parent
7bd5e2fa95
commit
c8c62dda9d
6 changed files with 171 additions and 10 deletions
|
|
@ -15,11 +15,11 @@ import { ExternalLinkAltIcon } from '@patternfly/react-icons';
|
|||
|
||||
import ClonesTable from './ClonesTable';
|
||||
|
||||
import { useGetComposeStatusQuery } from '../../store/backendApi';
|
||||
import { extractProvisioningList } from '../../store/helpers';
|
||||
import {
|
||||
ComposesResponseItem,
|
||||
GcpUploadRequestOptions,
|
||||
useGetComposeStatusQuery,
|
||||
} from '../../store/imageBuilderApi';
|
||||
import { useGetSourceListQuery } from '../../store/provisioningApi';
|
||||
import {
|
||||
|
|
@ -478,3 +478,36 @@ export const AwsS3Details = ({ compose }: AwsS3DetailsPropTypes) => {
|
|||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type LocalDetailsPropTypes = {
|
||||
compose: ComposesResponseItem;
|
||||
};
|
||||
|
||||
export const LocalDetails = ({ compose }: LocalDetailsPropTypes) => {
|
||||
return (
|
||||
<>
|
||||
<div className="pf-v5-u-font-weight-bold pf-v5-u-pb-md">
|
||||
Build Information
|
||||
</div>
|
||||
<DescriptionList isHorizontal isCompact className=" pf-v5-u-pl-xl">
|
||||
<DescriptionListGroup>
|
||||
<DescriptionListTerm>UUID</DescriptionListTerm>
|
||||
<DescriptionListDescription>
|
||||
<ClipboardCopy
|
||||
hoverTip="Copy"
|
||||
clickTip="Copied"
|
||||
variant="inline-compact"
|
||||
ouiaId="other-targets-uuid"
|
||||
>
|
||||
{compose.id}
|
||||
</ClipboardCopy>
|
||||
</DescriptionListDescription>
|
||||
<DescriptionListTerm>Architecture</DescriptionListTerm>
|
||||
<DescriptionListDescription>
|
||||
{compose.request.image_requests[0].architecture}
|
||||
</DescriptionListDescription>
|
||||
</DescriptionListGroup>
|
||||
</DescriptionList>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,12 +33,18 @@ import {
|
|||
AwsS3Details,
|
||||
AzureDetails,
|
||||
GcpDetails,
|
||||
LocalDetails,
|
||||
OciDetails,
|
||||
} from './ImageDetails';
|
||||
import ImagesTableToolbar from './ImagesTableToolbar';
|
||||
import { AwsS3Instance, CloudInstance, OciInstance } from './Instance';
|
||||
import {
|
||||
AwsS3Instance,
|
||||
CloudInstance,
|
||||
OciInstance,
|
||||
LocalInstance,
|
||||
} from './Instance';
|
||||
import Release from './Release';
|
||||
import { ExpiringStatus, CloudStatus } from './Status';
|
||||
import { ExpiringStatus, CloudStatus, LocalStatus } from './Status';
|
||||
import { AwsTarget, Target } from './Target';
|
||||
|
||||
import {
|
||||
|
|
@ -50,6 +56,7 @@ import {
|
|||
STATUS_POLLING_INTERVAL,
|
||||
} from '../../constants';
|
||||
import {
|
||||
useGetComposeStatusQuery,
|
||||
useGetComposesQuery,
|
||||
useGetBlueprintsQuery,
|
||||
useGetBlueprintComposesQuery,
|
||||
|
|
@ -70,7 +77,6 @@ import {
|
|||
ComposeStatus,
|
||||
GetBlueprintComposesApiArg,
|
||||
GetBlueprintsApiArg,
|
||||
useGetComposeStatusQuery,
|
||||
} from '../../store/imageBuilderApi';
|
||||
import { resolveRelPath } from '../../Utilities/path';
|
||||
import {
|
||||
|
|
@ -300,10 +306,9 @@ const ImagesTableRow = ({ compose, rowIndex }: ImagesTableRowPropTypes) => {
|
|||
}
|
||||
}, [setPollingInterval, composeStatus]);
|
||||
|
||||
const type =
|
||||
compose.request?.image_requests[0]?.upload_request?.type || 'local';
|
||||
const type = compose.request?.image_requests[0]?.upload_request?.type;
|
||||
|
||||
switch (type) {
|
||||
switch (type as string) {
|
||||
case 'aws':
|
||||
return (
|
||||
<AwsRow
|
||||
|
|
@ -321,7 +326,7 @@ const ImagesTableRow = ({ compose, rowIndex }: ImagesTableRowPropTypes) => {
|
|||
case 'aws.s3':
|
||||
return <AwsS3Row compose={compose} rowIndex={rowIndex} />;
|
||||
case 'local':
|
||||
return <Row compose={compose} rowIndex={rowIndex} />;
|
||||
return <LocalRow compose={compose} rowIndex={rowIndex} />;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -463,6 +468,26 @@ const AwsRow = ({ compose, composeStatus, rowIndex }: AwsRowPropTypes) => {
|
|||
);
|
||||
};
|
||||
|
||||
type LocalRowPropTypes = {
|
||||
compose: ComposesResponseItem;
|
||||
rowIndex: number;
|
||||
};
|
||||
|
||||
const LocalRow = ({ compose, rowIndex }: LocalRowPropTypes) => {
|
||||
const details = <LocalDetails compose={compose} />;
|
||||
const instance = <LocalInstance compose={compose} />;
|
||||
const status = <LocalStatus compose={compose} />;
|
||||
return (
|
||||
<Row
|
||||
compose={compose}
|
||||
rowIndex={rowIndex}
|
||||
details={details}
|
||||
instance={instance}
|
||||
status={status}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
type RowPropTypes = {
|
||||
compose: ComposesResponseItem;
|
||||
rowIndex: number;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
SEARCH_INPUT,
|
||||
} from '../../constants';
|
||||
import { useGetBlueprintsQuery } from '../../store/backendApi';
|
||||
import { useGetComposeStatusQuery } from '../../store/backendApi';
|
||||
import {
|
||||
selectSelectedBlueprintId,
|
||||
selectBlueprintSearchInput,
|
||||
|
|
@ -37,7 +38,6 @@ import {
|
|||
ComposesResponseItem,
|
||||
ComposeStatus,
|
||||
ImageTypes,
|
||||
useGetComposeStatusQuery,
|
||||
} from '../../store/imageBuilderApi';
|
||||
import {
|
||||
isAwsUploadRequestOptions,
|
||||
|
|
@ -403,3 +403,31 @@ export const AwsS3Instance = ({
|
|||
);
|
||||
}
|
||||
};
|
||||
|
||||
type LocalInstancePropTypes = {
|
||||
compose: ComposesResponseItem;
|
||||
};
|
||||
|
||||
export const LocalInstance = ({ compose }: LocalInstancePropTypes) => {
|
||||
const { data: composeStatus, isSuccess } = useGetComposeStatusQuery({
|
||||
composeId: compose.id,
|
||||
});
|
||||
if (!isSuccess) {
|
||||
return <Skeleton />;
|
||||
}
|
||||
|
||||
// Hacky to define the type here, but local upload is not available in
|
||||
// the image builder api, only in the composer api.
|
||||
type LocalUploadStatusOptions = {
|
||||
filename: string;
|
||||
};
|
||||
const status = composeStatus?.image_status.status;
|
||||
const options = composeStatus?.image_status.upload_status
|
||||
?.options as unknown as LocalUploadStatusOptions;
|
||||
|
||||
if (status !== 'success') {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return <div>Filepath to disk: {options.filename}</div>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ import {
|
|||
AWS_S3_EXPIRATION_TIME_IN_HOURS,
|
||||
OCI_STORAGE_EXPIRATION_TIME_IN_DAYS,
|
||||
} from '../../constants';
|
||||
import { useGetComposeStatusQuery } from '../../store/backendApi';
|
||||
import {
|
||||
ClonesResponseItem,
|
||||
ComposeStatus,
|
||||
ComposeStatusError,
|
||||
ComposesResponseItem,
|
||||
UploadStatus,
|
||||
useGetComposeStatusQuery,
|
||||
} from '../../store/imageBuilderApi';
|
||||
|
||||
type StatusClonePropTypes = {
|
||||
|
|
@ -213,6 +213,33 @@ export const ExpiringStatus = ({
|
|||
}
|
||||
};
|
||||
|
||||
type LocalStatusPropTypes = {
|
||||
compose: ComposesResponseItem;
|
||||
};
|
||||
|
||||
export const LocalStatus = ({ compose }: LocalStatusPropTypes) => {
|
||||
const { data: composeStatus, isSuccess } = useGetComposeStatusQuery({
|
||||
composeId: compose.id,
|
||||
});
|
||||
|
||||
if (!isSuccess) {
|
||||
return <Skeleton />;
|
||||
}
|
||||
|
||||
const status = composeStatus?.image_status.status || 'failure';
|
||||
|
||||
if (status === 'failure') {
|
||||
return (
|
||||
<ErrorStatus
|
||||
icon={statuses[status].icon}
|
||||
text={statuses[status].text}
|
||||
error={composeStatus?.image_status.error || ''}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <Status icon={statuses[status].icon} text={statuses[status].text} />;
|
||||
};
|
||||
|
||||
const statuses = {
|
||||
failure: {
|
||||
icon: <ExclamationCircleIcon className="error" />,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ export const useGetBlueprintComposesQuery = process.env.IS_ON_PREMISE
|
|||
? cockpitQueries.useGetBlueprintComposesQuery
|
||||
: imageBuilderQueries.useGetBlueprintComposesQuery;
|
||||
|
||||
export const useGetComposeStatusQuery = process.env.IS_ON_PREMISE
|
||||
? cockpitQueries.useGetComposeStatusQuery
|
||||
: imageBuilderQueries.useGetComposeStatusQuery;
|
||||
|
||||
export const useBackendPrefetch = process.env.IS_ON_PREMISE
|
||||
? cockpitApi.usePrefetch
|
||||
: imageBuilderApi.usePrefetch;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ import {
|
|||
GetBlueprintComposesApiResponse,
|
||||
GetComposesApiArg,
|
||||
GetComposesApiResponse,
|
||||
GetComposeStatusApiArg,
|
||||
GetComposeStatusApiResponse,
|
||||
DeleteBlueprintApiResponse,
|
||||
DeleteBlueprintApiArg,
|
||||
BlueprintItem,
|
||||
|
|
@ -418,6 +420,47 @@ export const cockpitApi = emptyCockpitApi.injectEndpoints({
|
|||
}
|
||||
},
|
||||
}),
|
||||
getComposeStatus: builder.query<
|
||||
GetComposeStatusApiResponse,
|
||||
GetComposeStatusApiArg
|
||||
>({
|
||||
queryFn: async (queryArg) => {
|
||||
try {
|
||||
const cloudapi = cockpit.http('/run/cloudapi/api.socket', {
|
||||
superuser: 'require',
|
||||
});
|
||||
const resp = JSON.parse(
|
||||
await cloudapi.get(
|
||||
`/api/image-builder-composer/v2/composes/${queryArg.composeId}`
|
||||
)
|
||||
);
|
||||
const blueprintsDir = await getBlueprintsPath();
|
||||
const info = await fsinfo(blueprintsDir, ['entries'], {
|
||||
superuser: 'try',
|
||||
});
|
||||
const entries = Object.entries(info?.entries || {});
|
||||
for (const bpEntry of entries) {
|
||||
const request = await cockpit
|
||||
.file(path.join(blueprintsDir, bpEntry[0], queryArg.composeId))
|
||||
.read();
|
||||
return {
|
||||
data: {
|
||||
image_status: resp.image_status,
|
||||
request: JSON.parse(request),
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
data: {
|
||||
image_status: '',
|
||||
request: {},
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
return { error };
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
@ -434,4 +477,5 @@ export const {
|
|||
useComposeBlueprintMutation,
|
||||
useGetComposesQuery,
|
||||
useGetBlueprintComposesQuery,
|
||||
useGetComposeStatusQuery,
|
||||
} = cockpitApi;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue