@@ -9,6 +9,7 @@ import path from 'path';
9
9
import TOML , { Section } from '@ltd/j-toml' ;
10
10
import cockpit from 'cockpit' ;
11
11
import { fsinfo } from 'cockpit/fsinfo' ;
12
+ import { LongRunningProcess } from 'long-running-process' ;
12
13
import { v4 as uuidv4 } from 'uuid' ;
13
14
14
15
// We have to work around RTK query here, since it doesn't like splitting
@@ -19,17 +20,21 @@ import { v4 as uuidv4 } from 'uuid';
19
20
// bit so that the `cockpitApi` doesn't become a monolith.
20
21
import { contentSourcesApi } from './contentSourcesApi' ;
21
22
import {
23
+ ComposeStatus ,
24
+ composeStatus ,
22
25
datastreamDistroLookup ,
23
26
getBlueprintsPath ,
24
27
getCloudConfigs ,
25
- mapToOnpremRequest ,
26
28
paginate ,
27
29
readComposes ,
30
+ updateComposeStatus ,
28
31
} from './helpers' ;
29
32
import type {
30
33
CockpitCreateBlueprintApiArg ,
31
34
CockpitCreateBlueprintRequest ,
32
35
CockpitUpdateBlueprintApiArg ,
36
+ GetCockpitComposeStatusApiResponse ,
37
+ ImageStatus ,
33
38
UpdateWorkerConfigApiArg ,
34
39
WorkerConfigFile ,
35
40
WorkerConfigResponse ,
@@ -39,6 +44,7 @@ import {
39
44
mapHostedToOnPrem ,
40
45
mapOnPremToHosted ,
41
46
} from '../../Components/Blueprints/helpers/onPremToHostedBlueprintMapper' ;
47
+ import { ARTIFACTS_DIR } from '../../constants' ;
42
48
import {
43
49
BlueprintItem ,
44
50
ComposeBlueprintApiArg ,
@@ -61,7 +67,6 @@ import {
61
67
GetComposesApiArg ,
62
68
GetComposesApiResponse ,
63
69
GetComposeStatusApiArg ,
64
- GetComposeStatusApiResponse ,
65
70
GetOscapCustomizationsApiArg ,
66
71
GetOscapCustomizationsApiResponse ,
67
72
GetOscapProfilesApiArg ,
@@ -359,7 +364,7 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
359
364
ComposeBlueprintApiResponse ,
360
365
ComposeBlueprintApiArg
361
366
> ( {
362
- queryFn : async ( { id : filename } , _ , __ , baseQuery ) => {
367
+ queryFn : async ( { id : filename } ) => {
363
368
try {
364
369
const blueprintsDir = await getBlueprintsPath ( ) ;
365
370
const file = cockpit . file (
@@ -386,29 +391,63 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
386
391
image_requests : [ ir ] ,
387
392
} ;
388
393
389
- const composeResp = await baseQuery ( {
390
- url : '/compose' ,
391
- method : 'POST' ,
392
- body : JSON . stringify (
393
- // since this is the request that gets sent to the cloudapi
394
- // backend, we need to modify it slightly
395
- mapToOnpremRequest (
394
+ const uuid = uuidv4 ( ) ;
395
+ const composeDir = path . join ( blueprintsDir , filename , uuid ) ;
396
+ await cockpit . spawn ( [ 'mkdir' , '-p' , composeDir ] , { } ) ;
397
+
398
+ const ibBpPath = path . join ( composeDir , 'bp.json' ) ;
399
+ await cockpit
400
+ . file ( ibBpPath )
401
+ . replace (
402
+ JSON . stringify (
396
403
mapHostedToOnPrem ( blueprint as CreateBlueprintRequest ) ,
397
- crcComposeRequest . distribution ,
398
- [ ir ] ,
404
+ null ,
405
+ 2 ,
399
406
) ,
400
- null ,
401
- 2 ,
402
- ) ,
403
- headers : {
404
- 'content-type' : 'application/json' ,
405
- } ,
406
- } ) ;
407
+ ) ;
407
408
409
+ // save the blueprint request early, since any errors
410
+ // in this function cause pretty big headaches with
411
+ // the images table
408
412
await cockpit
409
- . file ( path . join ( blueprintsDir , filename , composeResp . data ?. id ) )
413
+ . file ( path . join ( composeDir , 'request.json' ) )
410
414
. replace ( JSON . stringify ( crcComposeRequest , null , 2 ) ) ;
411
- composes . push ( { id : composeResp . data ?. id } ) ;
415
+
416
+ const user = await cockpit . user ( ) ;
417
+ const cmd = [
418
+ // the image build fails if we don't set
419
+ // this for some reason
420
+ `HOME=${ user . home } ` ,
421
+ '/usr/bin/image-builder' ,
422
+ 'build' ,
423
+ '--with-buildlog' ,
424
+ '--blueprint' ,
425
+ ibBpPath ,
426
+ '--output-dir' ,
427
+ path . join ( ARTIFACTS_DIR , uuid ) ,
428
+ '--output-name' ,
429
+ uuid ,
430
+ '--distro' ,
431
+ crcComposeRequest . distribution ,
432
+ ir . image_type ,
433
+ ] ;
434
+
435
+ const process = new LongRunningProcess (
436
+ `cockpit-image-builder-${ uuid } .service` ,
437
+ updateComposeStatus ( composeDir ) ,
438
+ ) ;
439
+
440
+ // this is a workaround because the process
441
+ // can't be started when in `init` state
442
+ process . state = 'stopped' ;
443
+
444
+ process . run ( [ 'bash' , '-ec' , cmd . join ( ' ' ) ] ) . catch ( async ( ) => {
445
+ await cockpit
446
+ . file ( path . join ( composeDir , 'result' ) )
447
+ . replace ( ComposeStatus . FAILURE ) ;
448
+ } ) ;
449
+
450
+ composes . push ( { id : uuid } ) ;
412
451
}
413
452
414
453
return {
@@ -452,37 +491,47 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
452
491
} ,
453
492
} ) ,
454
493
getComposeStatus : builder . query <
455
- GetComposeStatusApiResponse ,
494
+ GetCockpitComposeStatusApiResponse ,
456
495
GetComposeStatusApiArg
457
496
> ( {
458
- queryFn : async ( queryArg , _ , __ , baseQuery ) => {
497
+ queryFn : async ( queryArg ) => {
459
498
try {
460
- const resp = await baseQuery ( {
461
- url : `/composes/${ queryArg . composeId } ` ,
462
- method : 'GET' ,
463
- } ) ;
464
499
const blueprintsDir = await getBlueprintsPath ( ) ;
465
500
const info = await fsinfo ( blueprintsDir , [ 'entries' ] , {
466
501
superuser : 'try' ,
467
502
} ) ;
468
503
const entries = Object . entries ( info ?. entries || { } ) ;
469
- for ( const bpEntry of entries ) {
504
+ for await ( const bpEntry of entries ) {
505
+ const bpComposes = await readComposes ( bpEntry [ 0 ] ) ;
506
+ if ( ! bpComposes . some ( ( c ) => c . id === queryArg . composeId ) ) {
507
+ continue ;
508
+ }
509
+
470
510
const request = await cockpit
471
- . file ( path . join ( blueprintsDir , bpEntry [ 0 ] , queryArg . composeId ) )
511
+ . file (
512
+ path . join (
513
+ blueprintsDir ,
514
+ bpEntry [ 0 ] ,
515
+ queryArg . composeId ,
516
+ 'request.json' ,
517
+ ) ,
518
+ )
472
519
. read ( ) ;
520
+
521
+ const status = await composeStatus (
522
+ queryArg . composeId ,
523
+ path . join ( blueprintsDir , bpEntry [ 0 ] , queryArg . composeId ) ,
524
+ ) ;
525
+
473
526
return {
474
527
data : {
475
- image_status : resp . data ?. image_status ,
528
+ image_status : status as ImageStatus ,
476
529
request : JSON . parse ( request ) ,
477
530
} ,
478
531
} ;
479
532
}
480
- return {
481
- data : {
482
- image_status : '' ,
483
- request : { } ,
484
- } ,
485
- } ;
533
+
534
+ throw new Error ( 'Compose not found' ) ;
486
535
} catch ( error ) {
487
536
return { error } ;
488
537
}
0 commit comments