Skip to content

Commit 21629f6

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 580023f commit 21629f6

File tree

3 files changed

+142
-153
lines changed

3 files changed

+142
-153
lines changed

src/store/cockpit/cockpitApi.ts

Lines changed: 12 additions & 152 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+
getBlueprintsPath,
23+
getCloudConfigs,
24+
lookupDatastreamDistro,
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
}
@@ -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
}

src/store/cockpit/helpers.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import path from 'path';
2+
3+
import TOML from '@ltd/j-toml';
4+
import cockpit from 'cockpit';
5+
import { fsinfo } from 'cockpit/fsinfo';
6+
7+
import { Blueprint } from './composerCloudApi';
8+
import { CockpitImageRequest } from './types';
9+
10+
import { BLUEPRINTS_DIR } from '../../constants';
11+
import { ComposesResponseItem } from '../imageBuilderApi';
12+
13+
export const lookupDatastreamDistro = (distribution: string) => {
14+
if (distribution.startsWith('fedora')) {
15+
return 'fedora';
16+
}
17+
18+
if (distribution === 'centos-9') {
19+
return 'cs9';
20+
}
21+
22+
if (distribution === 'centos-10') {
23+
return 'cs10';
24+
}
25+
26+
if (distribution === 'rhel-9') {
27+
return 'rhel9';
28+
}
29+
30+
if (distribution === 'rhel-10') {
31+
return 'rhel10';
32+
}
33+
34+
throw 'Unknown distribution';
35+
};
36+
37+
export const getBlueprintsPath = async () => {
38+
const user = await cockpit.user();
39+
40+
// we will use the user's `.local` directory
41+
// to save blueprints used for on-prem
42+
return `${user.home}/${BLUEPRINTS_DIR}`;
43+
};
44+
45+
export const readComposes = async (bpID: string) => {
46+
const blueprintsDir = await getBlueprintsPath();
47+
let composes: ComposesResponseItem[] = [];
48+
const bpInfo = await fsinfo(
49+
path.join(blueprintsDir, bpID),
50+
['entries', 'mtime'],
51+
{
52+
superuser: 'try',
53+
},
54+
);
55+
const bpEntries = Object.entries(bpInfo?.entries || {});
56+
for (const entry of bpEntries) {
57+
if (entry[0] === `${bpID}.json`) {
58+
continue;
59+
}
60+
const composeReq = await cockpit
61+
.file(path.join(blueprintsDir, bpID, entry[0]))
62+
.read();
63+
composes = [
64+
...composes,
65+
{
66+
id: entry[0],
67+
request: JSON.parse(composeReq),
68+
created_at: new Date(entry[1]!.mtime * 1000).toString(),
69+
blueprint_id: bpID,
70+
},
71+
];
72+
}
73+
return composes;
74+
};
75+
76+
export const getCloudConfigs = async () => {
77+
try {
78+
const worker_config = cockpit.file(
79+
'/etc/osbuild-worker/osbuild-worker.toml',
80+
);
81+
const contents = await worker_config.read();
82+
const parsed = TOML.parse(contents);
83+
return Object.keys(parsed).filter((k) => k === 'aws');
84+
} catch {
85+
return [];
86+
}
87+
};
88+
89+
export const mapToOnpremRequest = (
90+
blueprint: Blueprint,
91+
distribution: string,
92+
image_requests: CockpitImageRequest[],
93+
) => {
94+
return {
95+
blueprint,
96+
distribution,
97+
image_requests: image_requests.map((ir) => ({
98+
architecture: ir.architecture,
99+
image_type: ir.image_type,
100+
repositories: [],
101+
upload_targets: [
102+
{
103+
type: ir.upload_request.type,
104+
upload_options: ir.upload_request.options,
105+
},
106+
],
107+
})),
108+
};
109+
};
110+
111+
export const paginate = <T extends { id: string }>(
112+
items: T[],
113+
offset?: number | undefined,
114+
limit?: number | undefined,
115+
) => {
116+
const first = items.length > 0 ? items[0].id : '';
117+
const last = items.length > 0 ? items[items.length - 1].id : '';
118+
119+
return {
120+
data: {
121+
meta: { count: items.length },
122+
links: {
123+
first: first,
124+
last: last,
125+
},
126+
data: items.slice(offset ?? 0, limit ?? 100),
127+
},
128+
};
129+
};

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)