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

src: add custom repositories import feature #2626

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions api/config/contentSources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const config: ConfigFile = {
'searchPackageGroup',
'listFeatures',
'listSnapshotsByDate',
'bulkImportRepositories',
],
};

Expand Down
9,601 changes: 4,879 additions & 4,722 deletions api/schema/compliance.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions api/schema/imageBuilder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1081,13 +1081,17 @@ components:
required:
- parent_id
- exported_at
- is_on_prem
properties:
parent_id:
type: string
format: uuid
nullable: true
exported_at:
type: string
is_on_prem:
type: boolean
default: false
Distributions:
type: string
description: |
Expand Down
15 changes: 14 additions & 1 deletion src/Components/Blueprints/ImportBlueprintModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ import { mapOnPremToHosted } from './helpers/onPremToHostedBlueprintMapper';

import { useAppDispatch } from '../../store/hooks';
import { BlueprintExportResponse } from '../../store/imageBuilderApi';
import { wizardState } from '../../store/wizardSlice';
import { importCustomRepositories, wizardState } from '../../store/wizardSlice';
import { resolveRelPath } from '../../Utilities/path';
import { mapExportRequestToState } from '../CreateImageWizard/utilities/requestMapper';
import { ApiRepositoryRequest, useBulkImportRepositoriesMutation } from '../../store/contentSourcesApi';

interface ImportBlueprintModalProps {
setShowImportModal: React.Dispatch<React.SetStateAction<boolean>>;
Expand All @@ -50,6 +51,7 @@ export const ImportBlueprintModal: React.FunctionComponent<
const [isRejected, setIsRejected] = React.useState(false);
const [isOnPrem, setIsOnPrem] = React.useState(false);
const dispatch = useAppDispatch();
const [importRepositories, repositoriesResult] = useBulkImportRepositoriesMutation();

const handleFileInputChange = (
_event: React.ChangeEvent<HTMLInputElement> | React.DragEvent<HTMLElement>,
Expand Down Expand Up @@ -83,11 +85,22 @@ export const ImportBlueprintModal: React.FunctionComponent<
distribution: blueprintFromFile.distribution,
customizations: blueprintFromFile.customizations,
metadata: blueprintFromFile.metadata,
content_sources: blueprintFromFile.content_sources,
};
const importBlueprintState = mapExportRequestToState(
blueprintExportedResponse,
blueprintFromFile.image_requests || []
);
if (blueprintExportedResponse.content_sources) {
const customRepositories: ApiRepositoryRequest[] = blueprintExportedResponse.content_sources.map(item => item as ApiRepositoryRequest);
const result = importRepositories({
body: customRepositories,
});
dispatch(
importCustomRepositories(blueprintExportedResponse.customizations.custom_repositories || [])
);
};

setImportedBlueprint(importBlueprintState);
}
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export const mapOnPremToHosted = (
metadata: {
parent_id: null,
exported_at: '',
is_on_prem: false,
},
};
};
4 changes: 2 additions & 2 deletions src/Components/CreateImageWizard/utilities/requestMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ import {
selectSnapshotDate,
selectUseLatest,
selectFirstBootScript,
selectMetadata,
initialState,
} from '../../../store/wizardSlice';
import { FileSystemConfigurationType } from '../steps/FileSystem';
Expand Down Expand Up @@ -108,7 +107,7 @@ export const mapRequestFromState = (

return {
name: selectBlueprintName(state),
metadata: selectMetadata(state),
// metadata: selectMetadata(state),
description: selectBlueprintDescription(state),
distribution: selectDistribution(state),
image_requests: imageRequests,
Expand Down Expand Up @@ -343,6 +342,7 @@ export const mapExportRequestToState = (
customizations: request.customizations,
image_requests: image_requests,
};

return {
wizardMode,
metadata: {
Expand Down
127 changes: 127 additions & 0 deletions src/store/contentSourcesApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ const injectedRtkApi = api.injectEndpoints({
body: queryArg.apiRepositoryRequest,
}),
}),
bulkImportRepositories: build.mutation<
BulkImportRepositoriesApiResponse,
BulkImportRepositoriesApiArg
>({
query: (queryArg) => ({
url: `/repositories/bulk_import/`,
method: "POST",
body: queryArg.body,
}),
}),
listRepositoriesRpms: build.query<
ListRepositoriesRpmsApiResponse,
ListRepositoriesRpmsApiArg
Expand Down Expand Up @@ -129,6 +139,12 @@ export type CreateRepositoryApiArg = {
/** request body */
apiRepositoryRequest: ApiRepositoryRequest;
};
export type BulkImportRepositoriesApiResponse =
/** status 201 Created */ ApiRepositoryImportResponseRead[];
export type BulkImportRepositoriesApiArg = {
/** request body */
body: ApiRepositoryRequest[];
};
export type ListRepositoriesRpmsApiResponse =
/** status 200 OK */ ApiRepositoryRpmCollectionResponse;
export type ListRepositoriesRpmsApiArg = {
Expand Down Expand Up @@ -417,6 +433,116 @@ export type ApiRepositoryRequestRead = {
/** URL of the remote yum repository */
url?: string;
};
export type ApiRepositoryImportResponse = {
/** Content Type (rpm) of the repository */
content_type?: string;
/** Architecture to restrict client usage to */
distribution_arch?: string;
/** Versions to restrict client usage to */
distribution_versions?: string[];
/** Number of consecutive failed introspections */
failed_introspections_count?: number;
/** GPG key for repository */
gpg_key?: string;
/** Label used to configure the yum repository on clients */
label?: string;
/** Error of last attempted introspection */
last_introspection_error?: string;
/** Status of last introspection */
last_introspection_status?: string;
/** Timestamp of last attempted introspection */
last_introspection_time?: string;
last_snapshot?: ApiSnapshotResponse;
last_snapshot_task?: ApiTaskInfoResponse;
/** UUID of the last snapshot task */
last_snapshot_task_uuid?: string;
/** UUID of the last dao.Snapshot */
last_snapshot_uuid?: string;
/** Timestamp of last successful introspection */
last_success_introspection_time?: string;
/** Timestamp of last introspection that had updates */
last_update_introspection_time?: string;
/** Latest URL for the snapshot distribution */
latest_snapshot_url?: string;
/** Verify packages */
metadata_verification?: boolean;
/** Disable modularity filtering on this repository */
module_hotfixes?: boolean;
/** Name of the remote yum repository */
name?: string;
/** Origin of the repository */
origin?: string;
/** Number of packages last read in the repository */
package_count?: number;
/** Enable snapshotting and hosting of this repository */
snapshot?: boolean;
/** Combined status of last introspection and snapshot of repository (Valid, Invalid, Unavailable, Pending) */
status?: string;
/** URL of the remote yum repository */
url?: string;
/** Warnings to alert user of mismatched fields if there is an existing repo with the same URL */
warnings?: {
[key: string]: any;
}[];
};
export type ApiRepositoryImportResponseRead = {
/** Account ID of the owner */
account_id?: string;
/** Content Type (rpm) of the repository */
content_type?: string;
/** Architecture to restrict client usage to */
distribution_arch?: string;
/** Versions to restrict client usage to */
distribution_versions?: string[];
/** Number of consecutive failed introspections */
failed_introspections_count?: number;
/** GPG key for repository */
gpg_key?: string;
/** Label used to configure the yum repository on clients */
label?: string;
/** Error of last attempted introspection */
last_introspection_error?: string;
/** Status of last introspection */
last_introspection_status?: string;
/** Timestamp of last attempted introspection */
last_introspection_time?: string;
last_snapshot?: ApiSnapshotResponse;
last_snapshot_task?: ApiTaskInfoResponse;
/** UUID of the last snapshot task */
last_snapshot_task_uuid?: string;
/** UUID of the last dao.Snapshot */
last_snapshot_uuid?: string;
/** Timestamp of last successful introspection */
last_success_introspection_time?: string;
/** Timestamp of last introspection that had updates */
last_update_introspection_time?: string;
/** Latest URL for the snapshot distribution */
latest_snapshot_url?: string;
/** Verify packages */
metadata_verification?: boolean;
/** Disable modularity filtering on this repository */
module_hotfixes?: boolean;
/** Name of the remote yum repository */
name?: string;
/** Organization ID of the owner */
org_id?: string;
/** Origin of the repository */
origin?: string;
/** Number of packages last read in the repository */
package_count?: number;
/** Enable snapshotting and hosting of this repository */
snapshot?: boolean;
/** Combined status of last introspection and snapshot of repository (Valid, Invalid, Unavailable, Pending) */
status?: string;
/** URL of the remote yum repository */
url?: string;
/** UUID of the object */
uuid?: string;
/** Warnings to alert user of mismatched fields if there is an existing repo with the same URL */
warnings?: {
[key: string]: any;
}[];
};
export type ApiRepositoryRpm = {
/** The architecture of the rpm */
arch?: string;
Expand Down Expand Up @@ -469,6 +595,7 @@ export const {
useSearchPackageGroupMutation,
useListRepositoriesQuery,
useCreateRepositoryMutation,
useBulkImportRepositoriesMutation,
useListRepositoriesRpmsQuery,
useSearchRpmMutation,
useListSnapshotsByDateMutation,
Expand Down
1 change: 1 addition & 0 deletions src/store/imageBuilderApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@ export type Customizations = {
export type BlueprintMetadata = {
parent_id: string | null;
exported_at: string;
is_on_prem: boolean;
};
export type CreateBlueprintRequest = {
name: string;
Expand Down
12 changes: 11 additions & 1 deletion src/store/wizardSlice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
import { v4 as uuidv4 } from 'uuid';

import type { ApiRepositoryResponseRead } from './contentSourcesApi';
import type { ApiRepositoryImportResponseRead, ApiRepositoryRequest, ApiRepositoryResponseRead } from './contentSourcesApi';
import type {
CustomRepository,
Distributions,
Expand Down Expand Up @@ -577,6 +577,15 @@ export const wizardSlice = createSlice({
changeSnapshotDate: (state, action: PayloadAction<string>) => {
state.snapshotting.snapshotDate = action.payload;
},
importCustomRepositories: (
state,
action: PayloadAction<CustomRepository[]>
) => {
state.repositories.customRepositories = [
...state.repositories.customRepositories,
...action.payload
]
},
changeCustomRepositories: (
state,
action: PayloadAction<CustomRepository[]>
Expand Down Expand Up @@ -711,6 +720,7 @@ export const {
changeUseLatest,
changeSnapshotDate,
changeCustomRepositories,
importCustomRepositories,
changePayloadRepositories,
addRecommendedRepository,
removeRecommendedRepository,
Expand Down