Skip to content

Commit 4054a46

Browse files
store/cockpitApi: extract helpers into their own file
This change refactors some of the cockpit api file end extracts all the helper functions to their own file. This just makes the file more manageable to work with.
1 parent a137173 commit 4054a46

File tree

9 files changed

+147
-155
lines changed

9 files changed

+147
-155
lines changed

src/store/cockpit/cockpitApi.ts

Lines changed: 14 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,24 @@ import cockpit from 'cockpit';
1111
import { fsinfo } from 'cockpit/fsinfo';
1212
import { v4 as uuidv4 } from 'uuid';
1313

14-
import { Blueprint } from './composerCloudApi';
1514
// We have to work around RTK query here, since it doesn't like splitting
1615
// out the same api into two separate apis. So, instead, we can just
1716
// inherit/import the `contentSourcesApi` and build on top of that.
1817
// This is fine since all the api endpoints for on-prem should query
1918
// the same unix socket. This allows us to split out the code a little
2019
// bit so that the `cockpitApi` doesn't become a monolith.
2120
import { contentSourcesApi } from './contentSourcesApi';
21+
import {
22+
datastreamDistroLookup,
23+
getBlueprintsPath,
24+
getCloudConfigs,
25+
mapToOnpremRequest,
26+
paginate,
27+
readComposes,
28+
} from './helpers';
2229
import type {
2330
CockpitCreateBlueprintApiArg,
2431
CockpitCreateBlueprintRequest,
25-
CockpitImageRequest,
2632
CockpitUpdateBlueprintApiArg,
2733
UpdateWorkerConfigApiArg,
2834
WorkerConfigFile,
@@ -33,7 +39,6 @@ import {
3339
mapHostedToOnPrem,
3440
mapOnPremToHosted,
3541
} from '../../Components/Blueprints/helpers/onPremToHostedBlueprintMapper';
36-
import { BLUEPRINTS_DIR } from '../../constants';
3742
import {
3843
BlueprintItem,
3944
ComposeBlueprintApiArg,
@@ -64,104 +69,6 @@ import {
6469
UpdateBlueprintApiResponse,
6570
} from '../service/imageBuilderApi';
6671

67-
const lookupDatastreamDistro = (distribution: string) => {
68-
if (distribution.startsWith('fedora')) {
69-
return 'fedora';
70-
}
71-
72-
if (distribution === 'centos-9') {
73-
return 'cs9';
74-
}
75-
76-
if (distribution === 'centos-10') {
77-
return 'cs10';
78-
}
79-
80-
if (distribution === 'rhel-9') {
81-
return 'rhel9';
82-
}
83-
84-
if (distribution === 'rhel-10') {
85-
return 'rhel10';
86-
}
87-
88-
throw 'Unknown distribution';
89-
};
90-
91-
const getBlueprintsPath = async () => {
92-
const user = await cockpit.user();
93-
94-
// we will use the user's `.local` directory
95-
// to save blueprints used for on-prem
96-
return `${user.home}/${BLUEPRINTS_DIR}`;
97-
};
98-
99-
const readComposes = async (bpID: string) => {
100-
const blueprintsDir = await getBlueprintsPath();
101-
let composes: ComposesResponseItem[] = [];
102-
const bpInfo = await fsinfo(
103-
path.join(blueprintsDir, bpID),
104-
['entries', 'mtime'],
105-
{
106-
superuser: 'try',
107-
},
108-
);
109-
const bpEntries = Object.entries(bpInfo?.entries || {});
110-
for (const entry of bpEntries) {
111-
if (entry[0] === `${bpID}.json`) {
112-
continue;
113-
}
114-
const composeReq = await cockpit
115-
.file(path.join(blueprintsDir, bpID, entry[0]))
116-
.read();
117-
composes = [
118-
...composes,
119-
{
120-
id: entry[0],
121-
request: JSON.parse(composeReq),
122-
created_at: new Date(entry[1]!.mtime * 1000).toString(),
123-
blueprint_id: bpID,
124-
},
125-
];
126-
}
127-
return composes;
128-
};
129-
130-
const getCloudConfigs = async () => {
131-
try {
132-
const worker_config = cockpit.file(
133-
'/etc/osbuild-worker/osbuild-worker.toml',
134-
);
135-
const contents = await worker_config.read();
136-
const parsed = TOML.parse(contents);
137-
return Object.keys(parsed).filter((k) => k === 'aws');
138-
} catch {
139-
return [];
140-
}
141-
};
142-
143-
const mapToOnpremRequest = (
144-
blueprint: Blueprint,
145-
distribution: string,
146-
image_requests: CockpitImageRequest[],
147-
) => {
148-
return {
149-
blueprint,
150-
distribution,
151-
image_requests: image_requests.map((ir) => ({
152-
architecture: ir.architecture,
153-
image_type: ir.image_type,
154-
repositories: [],
155-
upload_targets: [
156-
{
157-
type: ir.upload_request.type,
158-
upload_options: ir.upload_request.options,
159-
},
160-
],
161-
})),
162-
};
163-
};
164-
16572
export const cockpitApi = contentSourcesApi.injectEndpoints({
16673
endpoints: (builder) => {
16774
return {
@@ -278,31 +185,7 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
278185
return true;
279186
});
280187

281-
let paginatedBlueprints = blueprints;
282-
if (offset !== undefined && limit !== undefined) {
283-
paginatedBlueprints = blueprints.slice(offset, offset + limit);
284-
}
285-
286-
let first = '';
287-
let last = '';
288-
289-
if (blueprints.length > 0) {
290-
first = blueprints[0].id;
291-
last = blueprints[blueprints.length - 1].id;
292-
}
293-
294-
return {
295-
data: {
296-
meta: { count: blueprints.length },
297-
links: {
298-
// These are kind of meaningless for the on-prem
299-
// version
300-
first: first,
301-
last: last,
302-
},
303-
data: paginatedBlueprints,
304-
},
305-
};
188+
return paginate(blueprints, offset, limit);
306189
} catch (error) {
307190
return { error };
308191
}
@@ -380,7 +263,7 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
380263
>({
381264
queryFn: async ({ distribution }) => {
382265
try {
383-
const dsDistro = lookupDatastreamDistro(distribution);
266+
const dsDistro = datastreamDistroLookup(distribution);
384267
const result = (await cockpit.spawn(
385268
[
386269
'oscap',
@@ -413,7 +296,7 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
413296
>({
414297
queryFn: async ({ distribution, profile }) => {
415298
try {
416-
const dsDistro = lookupDatastreamDistro(distribution);
299+
const dsDistro = datastreamDistroLookup(distribution);
417300
let result = (await cockpit.spawn(
418301
[
419302
'oscap',
@@ -546,19 +429,8 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
546429
for (const entry of entries) {
547430
composes = composes.concat(await readComposes(entry[0]));
548431
}
549-
return {
550-
data: {
551-
meta: {
552-
count: composes.length,
553-
},
554-
links: {
555-
first: composes.length > 0 ? composes[0].id : '',
556-
last:
557-
composes.length > 0 ? composes[composes.length - 1].id : '',
558-
},
559-
data: composes,
560-
},
561-
};
432+
433+
return paginate(composes);
562434
} catch (error) {
563435
return { error };
564436
}
@@ -571,19 +443,7 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
571443
queryFn: async (queryArgs) => {
572444
try {
573445
const composes = await readComposes(queryArgs.id);
574-
return {
575-
data: {
576-
meta: {
577-
count: composes.length,
578-
},
579-
links: {
580-
first: composes.length > 0 ? composes[0].id : '',
581-
last:
582-
composes.length > 0 ? composes[composes.length - 1].id : '',
583-
},
584-
data: composes,
585-
},
586-
};
446+
return paginate(composes);
587447
} catch (error) {
588448
return { error };
589449
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import TOML from '@ltd/j-toml';
2+
import cockpit from 'cockpit';
3+
4+
export const getCloudConfigs = async () => {
5+
try {
6+
const worker_config = cockpit.file(
7+
'/etc/osbuild-worker/osbuild-worker.toml',
8+
);
9+
const contents = await worker_config.read();
10+
const parsed = TOML.parse(contents);
11+
return Object.keys(parsed).filter((k) => k === 'aws');
12+
} catch {
13+
return [];
14+
}
15+
};

src/store/cockpit/helpers/composeStatus.ts

Whitespace-only changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export const datastreamDistroLookup = (distribution: string) => {
2+
if (distribution.startsWith('fedora')) {
3+
return 'fedora';
4+
}
5+
6+
if (distribution === 'centos-9') {
7+
return 'cs9';
8+
}
9+
10+
if (distribution === 'centos-10') {
11+
return 'cs10';
12+
}
13+
14+
if (distribution === 'rhel-9') {
15+
return 'rhel9';
16+
}
17+
18+
if (distribution === 'rhel-10') {
19+
return 'rhel10';
20+
}
21+
22+
throw 'Unknown distribution';
23+
};

src/store/cockpit/helpers/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export { getCloudConfigs } from './cloudConfig';
2+
export { datastreamDistroLookup } from './datastream';
3+
export { paginate } from './paginate';
4+
export { mapToOnpremRequest } from './onPremRequest';
5+
export { getBlueprintsPath, readComposes } from './readComposes';
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Blueprint } from '../composerCloudApi';
2+
import { CockpitImageRequest } from '../types';
3+
4+
export const mapToOnpremRequest = (
5+
blueprint: Blueprint,
6+
distribution: string,
7+
image_requests: CockpitImageRequest[],
8+
) => {
9+
return {
10+
blueprint,
11+
distribution,
12+
image_requests: image_requests.map((ir) => ({
13+
architecture: ir.architecture,
14+
image_type: ir.image_type,
15+
repositories: [],
16+
upload_targets: [
17+
{
18+
type: ir.upload_request.type,
19+
upload_options: ir.upload_request.options,
20+
},
21+
],
22+
})),
23+
};
24+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export const paginate = <T extends { id: string }>(
2+
items: T[],
3+
offset?: number | undefined,
4+
limit?: number | undefined,
5+
) => {
6+
const first = items.length > 0 ? items[0].id : '';
7+
const last = items.length > 0 ? items[items.length - 1].id : '';
8+
9+
return {
10+
data: {
11+
meta: { count: items.length },
12+
links: {
13+
first: first,
14+
last: last,
15+
},
16+
data: items.slice(offset ?? 0, limit ?? 100),
17+
},
18+
};
19+
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import path from 'path';
2+
3+
import cockpit from 'cockpit';
4+
import { fsinfo } from 'cockpit/fsinfo';
5+
6+
import { BLUEPRINTS_DIR } from '../../../constants';
7+
import { ComposesResponseItem } from '../../imageBuilderApi';
8+
9+
export const getBlueprintsPath = async () => {
10+
const user = await cockpit.user();
11+
12+
// we will use the user's `.local` directory
13+
// to save blueprints used for on-prem
14+
return `${user.home}/${BLUEPRINTS_DIR}`;
15+
};
16+
17+
export const readComposes = async (bpID: string) => {
18+
const blueprintsDir = await getBlueprintsPath();
19+
let composes: ComposesResponseItem[] = [];
20+
const bpInfo = await fsinfo(
21+
path.join(blueprintsDir, bpID),
22+
['entries', 'mtime'],
23+
{
24+
superuser: 'try',
25+
},
26+
);
27+
const bpEntries = Object.entries(bpInfo?.entries || {});
28+
for (const entry of bpEntries) {
29+
if (entry[0] === `${bpID}.json`) {
30+
continue;
31+
}
32+
const composeReq = await cockpit
33+
.file(path.join(blueprintsDir, bpID, entry[0]))
34+
.read();
35+
composes = [
36+
...composes,
37+
{
38+
id: entry[0],
39+
request: JSON.parse(composeReq),
40+
created_at: new Date(entry[1]!.mtime * 1000).toString(),
41+
blueprint_id: bpID,
42+
},
43+
];
44+
}
45+
return composes;
46+
};

src/test/mocks/cockpit/cockpitFile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export const cockpitFile = (filepath: string, _options?: object) => {
4444
return readCompose(file.name);
4545
},
4646
close: () => {},
47-
replace: (contents: string) => {
47+
replace: async (contents: string) => {
4848
const file = path.parse(filepath);
4949
const dir = path.parse(file.dir);
5050
if (file.name === dir.name) {

0 commit comments

Comments
 (0)