api: support linting and fixing of blueprints

This commit is contained in:
Sanne Raymaekers 2025-04-16 11:58:38 +02:00 committed by Klara Simickova
parent e222b13476
commit 2dde0f2177
8 changed files with 224 additions and 0 deletions

View file

@ -28,6 +28,7 @@ const config: ConfigFile = {
'deleteBlueprint',
'getBlueprint',
'recommendPackage',
'fixupBlueprint',
],
};

View file

@ -722,6 +722,27 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/RecommendationsResponse"
/experimental/blueprints/{id}/fixup:
parameters:
- in: path
name: id
schema:
type: string
format: uuid
example: '123e4567-e89b-12d3-a456-426655440000'
required: true
description: UUID of a blueprint
post:
summary: Apply linter fixes to blueprint
operationId: fixupBlueprint
description: |
Apply fixes which should fix any lint errors in the blueprint.
responses:
200:
description: successful update
404:
description: blueprint was not found
components:
schemas:
HTTPError:
@ -1028,6 +1049,7 @@ components:
- id
- name
- description
- lint
- distribution
- image_requests
- customizations
@ -1039,6 +1061,8 @@ components:
type: string
description:
type: string
lint:
$ref: "#/components/schemas/BlueprintLint"
distribution:
$ref: '#/components/schemas/Distributions'
image_requests:
@ -1097,6 +1121,29 @@ components:
is_on_prem:
type: boolean
default: false
BlueprintLint:
required:
- errors
description: |
Linting errors in the current blueprint, these might need to be resolved before the
blueprint can be used to build images again.
properties:
errors:
type: array
items:
$ref: '#/components/schemas/BlueprintLintItem'
BlueprintLintItem:
type: object
required:
- name
- description
properties:
name:
type: string
example: Compliance
description:
type: string
example: package a required by policy is not present
Distributions:
type: string
description: |
@ -1116,6 +1163,8 @@ components:
- rhel-8.10
- rhel-9
- rhel-9-nightly
- rhel-9.6-nightly
- rhel-9.7-nightly
- rhel-9-beta
- rhel-90
- rhel-91
@ -1124,6 +1173,8 @@ components:
- rhel-94
- rhel-95
- rhel-10-nightly
- rhel-10.0-nightly
- rhel-10.1-nightly
- rhel-10-beta
- centos-9
- centos-10
@ -1588,6 +1639,12 @@ components:
example: ['postgresql']
items:
type: string
enabled_modules:
type: array
description: |
List of dnf modules to enable, so that packages can be installed from them.
items:
$ref: '#/components/schemas/Module'
payload_repositories:
type: array
items:
@ -2118,3 +2175,20 @@ components:
type: boolean
module_hotfixes:
type: boolean
Module:
type: object
required:
- name
- stream
additionalProperties: false
properties:
name:
type: string
example: 'nodejs'
description: |
Name of the module to enable.
stream:
type: string
example: '22'
description: |
Stream to enable.

View file

@ -20,6 +20,8 @@ const Release = ({ release }: ReleaseProps) => {
'rhel-9': 'RHEL 9',
'rhel-9-beta': 'RHEL 9 Beta',
'rhel-9-nightly': 'RHEL 9',
'rhel-9.6-nightly': 'RHEL 9',
'rhel-9.7-nightly': 'RHEL 9',
'rhel-90': 'RHEL 9.0',
'rhel-91': 'RHEL 9.1',
'rhel-92': 'RHEL 9.2',
@ -27,6 +29,8 @@ const Release = ({ release }: ReleaseProps) => {
'rhel-94': 'RHEL 9.4',
'rhel-95': 'RHEL 9.5',
'rhel-10-nightly': 'RHEL 10',
'rhel-10.0-nightly': 'RHEL 10',
'rhel-10.1-nightly': 'RHEL 10',
'rhel-10-beta': 'RHEL 10 Beta',
'centos-8': 'CentOS Stream 8',
'centos-9': 'CentOS Stream 9',

View file

@ -171,6 +171,10 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
id,
version: version,
last_modified_at: new Date(bpInfo!.mtime * 1000).toString(),
// linting is not supported on prem
lint: {
errors: [],
},
},
};
} catch (error) {

View file

@ -222,6 +222,31 @@ const enhancedApi = imageBuilderApi.enhanceEndpoints({
});
},
},
fixupBlueprint: {
invalidatesTags: [{ type: 'Blueprint' }],
onQueryStarted: async (_, { dispatch, queryFulfilled }) => {
queryFulfilled
.then(() => {
dispatch(
addNotification({
variant: 'success',
title: 'Blueprint was fixed',
})
);
})
.catch((err) => {
dispatch(
addNotification({
variant: 'danger',
title: 'Blueprint could not be fixed',
description: `Status code ${err.error.status}: ${errorMessage(
err
)}`,
})
);
});
},
},
},
});

View file

@ -171,6 +171,15 @@ const injectedRtkApi = api.injectEndpoints({
body: queryArg.recommendPackageRequest,
}),
}),
fixupBlueprint: build.mutation<
FixupBlueprintApiResponse,
FixupBlueprintApiArg
>({
query: (queryArg) => ({
url: `/experimental/blueprints/${queryArg.id}/fixup`,
method: "POST",
}),
}),
}),
overrideExisting: false,
});
@ -335,6 +344,11 @@ export type RecommendPackageApiResponse =
export type RecommendPackageApiArg = {
recommendPackageRequest: RecommendPackageRequest;
};
export type FixupBlueprintApiResponse = unknown;
export type FixupBlueprintApiArg = {
/** UUID of a blueprint */
id: string;
};
export type Repository = {
/** An ID referring to a repository defined in content sources can be used instead of
'baseurl', 'mirrorlist' or 'metalink'.
@ -378,6 +392,8 @@ export type Distributions =
| "rhel-8.10"
| "rhel-9"
| "rhel-9-nightly"
| "rhel-9.6-nightly"
| "rhel-9.7-nightly"
| "rhel-9-beta"
| "rhel-90"
| "rhel-91"
@ -386,6 +402,8 @@ export type Distributions =
| "rhel-94"
| "rhel-95"
| "rhel-10-nightly"
| "rhel-10.0-nightly"
| "rhel-10.1-nightly"
| "rhel-10-beta"
| "centos-9"
| "centos-10"
@ -578,6 +596,14 @@ export type Subscription = {
*/
rhc?: boolean | undefined;
};
export type Module = {
/** Name of the module to enable.
*/
name: string;
/** Stream to enable.
*/
stream: string;
};
export type CustomRepository = {
id: string;
name?: string | undefined;
@ -711,6 +737,9 @@ export type Customizations = {
files?: File[] | undefined;
subscription?: Subscription | undefined;
packages?: string[] | undefined;
/** List of dnf modules to enable, so that packages can be installed from them.
*/
enabled_modules?: Module[] | undefined;
payload_repositories?: Repository[] | undefined;
/** List of custom repositories. */
custom_repositories?: CustomRepository[] | undefined;
@ -759,10 +788,18 @@ export type CreateBlueprintRequest = {
customizations: Customizations;
metadata?: BlueprintMetadata | undefined;
};
export type BlueprintLintItem = {
name: string;
description: string;
};
export type BlueprintLint = {
errors: BlueprintLintItem[];
};
export type BlueprintResponse = {
id: string;
name: string;
description: string;
lint: BlueprintLint;
distribution: Distributions;
/** Array of image requests. Having more image requests in a single blueprint is currently not supported.
*/
@ -959,4 +996,5 @@ export const {
useGetOscapCustomizationsQuery,
useLazyGetOscapCustomizationsQuery,
useRecommendPackageMutation,
useFixupBlueprintMutation,
} = injectedRtkApi;

View file

@ -545,6 +545,9 @@ export const multipleTargetsBlueprintResponse: GetBlueprintApiResponse = {
rhc: true,
},
},
lint: {
errors: [],
},
};
export const darkChocolateBlueprintResponse: GetBlueprintApiResponse = {
@ -561,4 +564,7 @@ export const darkChocolateBlueprintResponse: GetBlueprintApiResponse = {
rhc: true,
},
},
lint: {
errors: [],
},
};

View file

@ -186,6 +186,9 @@ export const rhel9BlueprintResponse: BlueprintResponse = {
...rhel9CreateBlueprintRequest,
id: mockBlueprintIds['rhel9'],
description: mockBlueprintDescriptions['rhel9'],
lint: {
errors: [],
},
};
export const rhel8CreateBlueprintRequest: CreateBlueprintRequest = {
@ -200,6 +203,9 @@ export const rhel8BlueprintResponse: BlueprintResponse = {
...rhel8CreateBlueprintRequest,
id: mockBlueprintIds['rhel8'],
description: mockBlueprintDescriptions['rhel8'],
lint: {
errors: [],
},
};
export const centos9CreateBlueprintRequest: CreateBlueprintRequest = {
@ -214,6 +220,9 @@ export const centos9BlueprintResponse: BlueprintResponse = {
...centos9CreateBlueprintRequest,
id: mockBlueprintIds['centos9'],
description: mockBlueprintDescriptions['centos9'],
lint: {
errors: [],
},
};
export const x86_64ImageRequest: ImageRequest = {
@ -232,6 +241,9 @@ export const x86_64BlueprintResponse: BlueprintResponse = {
...x86_64CreateBlueprintRequest,
id: mockBlueprintIds['x86_64'],
description: mockBlueprintDescriptions['x86_64'],
lint: {
errors: [],
},
};
export const aarch64ImageRequest: ImageRequest = {
@ -250,6 +262,9 @@ export const aarch64BlueprintResponse: BlueprintResponse = {
...aarch64CreateBlueprintRequest,
id: mockBlueprintIds['aarch64'],
description: mockBlueprintDescriptions['aarch64'],
lint: {
errors: [],
},
};
export const awsImageRequest: ImageRequest = {
@ -274,6 +289,9 @@ export const awsBlueprintResponse: BlueprintResponse = {
...awsCreateBlueprintRequest,
id: mockBlueprintIds['aws'],
description: mockBlueprintDescriptions['aws'],
lint: {
errors: [],
},
};
export const gcpImageRequest: ImageRequest = {
@ -298,6 +316,9 @@ export const gcpBlueprintResponse: BlueprintResponse = {
...gcpCreateBlueprintRequest,
id: mockBlueprintIds['gcp'],
description: mockBlueprintDescriptions['gcp'],
lint: {
errors: [],
},
};
export const azureImageRequest: ImageRequest = {
@ -324,6 +345,9 @@ export const azureBlueprintResponse: BlueprintResponse = {
...azureCreateBlueprintRequest,
id: mockBlueprintIds['azure'],
description: mockBlueprintDescriptions['azure'],
lint: {
errors: [],
},
};
export const registrationCreateBlueprintRequest: CreateBlueprintRequest = {
@ -339,6 +363,9 @@ export const registrationBlueprintResponse: BlueprintResponse = {
...registrationCreateBlueprintRequest,
id: mockBlueprintIds['registration'],
description: mockBlueprintDescriptions['registration'],
lint: {
errors: [],
},
};
export const oscapCreateBlueprintRequest: CreateBlueprintRequest = {
@ -358,6 +385,9 @@ export const oscapBlueprintResponse: BlueprintResponse = {
...oscapCreateBlueprintRequest,
id: mockBlueprintIds['oscap'],
description: mockBlueprintDescriptions['oscap'],
lint: {
errors: [],
},
};
export const fscCreateBlueprintRequest: CreateBlueprintRequest = {
@ -373,6 +403,9 @@ export const fscBlueprintResponse: BlueprintResponse = {
...fscCreateBlueprintRequest,
id: mockBlueprintIds['fsc'],
description: mockBlueprintDescriptions['fsc'],
lint: {
errors: [],
},
};
export const snapshotCreateBlueprintRequest: CreateBlueprintRequest = {
@ -389,6 +422,9 @@ export const snapshotBlueprintResponse: BlueprintResponse = {
...snapshotCreateBlueprintRequest,
id: mockBlueprintIds['snapshot'],
description: mockBlueprintDescriptions['snapshot'],
lint: {
errors: [],
},
};
export const repositoriesCreateBlueprintRequest: CreateBlueprintRequest = {
@ -405,6 +441,9 @@ export const repositoriesBlueprintResponse: BlueprintResponse = {
...repositoriesCreateBlueprintRequest,
id: mockBlueprintIds['repositories'],
description: mockBlueprintDescriptions['repositories'],
lint: {
errors: [],
},
};
export const packagesCreateBlueprintRequest: CreateBlueprintRequest = {
@ -420,6 +459,9 @@ export const packagesBlueprintResponse: BlueprintResponse = {
...packagesCreateBlueprintRequest,
id: mockBlueprintIds['packages'],
description: mockBlueprintDescriptions['packages'],
lint: {
errors: [],
},
};
export const timezoneCreateBlueprintRequest: CreateBlueprintRequest = {
@ -438,6 +480,9 @@ export const timezoneBlueprintResponse: BlueprintResponse = {
...timezoneCreateBlueprintRequest,
id: mockBlueprintIds['timezone'],
description: mockBlueprintDescriptions['timezone'],
lint: {
errors: [],
},
};
export const usersCreateBlueprintRequest: CreateBlueprintRequest = {
@ -459,6 +504,9 @@ export const usersBlueprintResponse: BlueprintResponse = {
...usersCreateBlueprintRequest,
id: mockBlueprintIds['users'],
description: mockBlueprintDescriptions['users'],
lint: {
errors: [],
},
};
export const localeCreateBlueprintRequest: CreateBlueprintRequest = {
@ -477,6 +525,9 @@ export const localeBlueprintResponse: BlueprintResponse = {
...localeCreateBlueprintRequest,
id: mockBlueprintIds['locale'],
description: mockBlueprintDescriptions['locale'],
lint: {
errors: [],
},
};
export const hostnameCreateBlueprintRequest: CreateBlueprintRequest = {
@ -492,6 +543,9 @@ export const hostnameBlueprintResponse: BlueprintResponse = {
...hostnameCreateBlueprintRequest,
id: mockBlueprintIds['hostname'],
description: mockBlueprintDescriptions['hostname'],
lint: {
errors: [],
},
};
export const kernelCreateBlueprintRequest: CreateBlueprintRequest = {
@ -510,6 +564,9 @@ export const kernelBlueprintResponse: BlueprintResponse = {
...kernelCreateBlueprintRequest,
id: mockBlueprintIds['kernel'],
description: mockBlueprintDescriptions['kernel'],
lint: {
errors: [],
},
};
export const firewallCreateBlueprintRequest: CreateBlueprintRequest = {
@ -539,6 +596,9 @@ export const firewallBlueprintResponse: BlueprintResponse = {
...firewallCreateBlueprintRequest,
id: mockBlueprintIds['firewall'],
description: mockBlueprintDescriptions['firewall'],
lint: {
errors: [],
},
};
export const servicesCreateBlueprintRequest: CreateBlueprintRequest = {
@ -554,6 +614,9 @@ export const servicesBlueprintResponse: BlueprintResponse = {
...servicesCreateBlueprintRequest,
id: mockBlueprintIds['services'],
description: mockBlueprintDescriptions['services'],
lint: {
errors: [],
},
};
export const firstBootCreateBlueprintRequest: CreateBlueprintRequest = {
@ -570,6 +633,9 @@ export const firstBootBlueprintResponse: BlueprintResponse = {
...firstBootCreateBlueprintRequest,
id: mockBlueprintIds['firstBoot'],
description: mockBlueprintDescriptions['firstBoot'],
lint: {
errors: [],
},
};
export const detailsCreateBlueprintRequest: CreateBlueprintRequest = {
@ -583,6 +649,9 @@ export const detailsBlueprintResponse: BlueprintResponse = {
...detailsCreateBlueprintRequest,
id: mockBlueprintIds['details'],
description: mockBlueprintDescriptions['details'],
lint: {
errors: [],
},
};
export const complianceCreateBlueprintRequest: CreateBlueprintRequest = {
@ -604,6 +673,9 @@ export const complianceBlueprintResponse: BlueprintResponse = {
...complianceCreateBlueprintRequest,
id: mockBlueprintIds['compliance'],
description: mockBlueprintDescriptions['compliance'],
lint: {
errors: [],
},
};
export const getMockBlueprintResponse = (id: string) => {