Subversion Repositories DevTools

Rev

Rev 7299 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5708 dpurdie 1
########################################################################
7300 dpurdie 2
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
5708 dpurdie 3
#
4
# Module name   : checkRelease.pl
5
# Module type   : JATS Utility
6
# Compiler(s)   : Perl
7
# Environment(s): jats
8
#
9
# Description   : Determine package that required for a Release/SBOM that are
10
#                 not in dpkg_archive.
11
#                 
12
#                 Such packages may need to be recovered from S3
13
#
14
# Usage         : See POD at the end of this file
15
#
16
#......................................................................#
17
 
18
require 5.006_001;
19
use strict;
20
use warnings;
21
use JatsEnv;
22
use JatsError;
23
use JatsSystem;
24
use JatsRmApi;
25
use FileUtils;
26
use DBI;
27
use Getopt::Long;
28
use Pod::Usage;                             # required for help support
29
 
30
#
31
#   Config Options
32
#
33
my $VERSION = "1.0.0";                      # Update this
34
my $opt_help = 0;
35
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
36
my $opt_sbom_id;
37
my $opt_rtag_id;
38
my $opt_test = 0;
39
my $opt_patch = 1;
40
my $opt_rootpkg;
41
my $opt_rootpkg_version;
5806 dpurdie 42
my $opt_extract;
5708 dpurdie 43
 
44
#
45
#   Data Base Interface
46
#
47
my $RM_DB;
48
my $DM_DB;
49
 
50
#
51
#   Global variables
52
#
53
my %os_id_list;                 # os_id in the SBOM
54
my %os_env_list;                # OS Environments
55
my %pv_id;                      # Packages in the SBOM
56
my %Package;                    # Per Package information
57
my %Release;                    # Release information
58
my %Release_pvid;               # Release info
59
my %Pegged;                     # Pegged/SDK packages by pvid - these do not need dependencies                                
60
my @StrayPackages;              # Non-top level packages
61
my @create_list;                # List of files created
62
my $fpref = "sbom";             # Sbom Prefix
63
our $GBE_DPKG;
64
my $sbom_name;
65
my $sbom_branch;
66
my $sbom_project;
67
my $sbom_version;
68
my $rtag_release;
69
my $rtag_project;
5806 dpurdie 70
my %config;
5708 dpurdie 71
 
72
#
73
#   Packages to be ignored
74
#
75
my %ignore;
76
my %patch;
77
 
78
 
79
#-------------------------------------------------------------------------------
80
# Function        : Main
81
#
82
# Description     : Main entry point
83
#                   Parse user options
84
#
85
# Inputs          :
86
#
87
# Returns         :
88
#
89
 
90
my $result = GetOptions (
91
                "help:+"            => \$opt_help,              # flag, multiple use allowed
92
                "manual:3"          => \$opt_help,              # flag, multiple use allowed
93
                "verbose:+"         => \$opt_verbose,           # flag
94
                "sbomid|sbom_id=s"  => \$opt_sbom_id,           # string
95
                "rtagid|rtag_id=s"  => \$opt_rtag_id,           # string
96
                "rootpackage=s"     => \$opt_rootpkg,           # String
97
                "ignore=s",         => sub{my ($a,$i) = @_; $ignore{$i} = 0 },
98
                "test!"             => \$opt_test,              #[no]flag
99
                "patch!"            => \$opt_patch,             #[no]flag
5806 dpurdie 100
                "extract=s"         => \$opt_extract,           # Name of file
5708 dpurdie 101
                );
102
 
103
#
104
#   Process help and manual options
105
#
106
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
107
pod2usage(-verbose => 1)  if ($opt_help == 2 );
108
pod2usage(-verbose => 2)  if ($opt_help > 2);
109
 
5806 dpurdie 110
ErrorConfig( 'name'    => 'CHECK',
5708 dpurdie 111
             'verbose' => $opt_verbose );
112
 
113
#
114
#   Sanity test
115
#
5806 dpurdie 116
unless ( $opt_rtag_id || $opt_sbom_id || $opt_extract || $#ARGV >= 1)
5708 dpurdie 117
{
118
    Error ("Need sbomid and/or rtagid",
119
           "Example: -sbomid=13543, for NZS Phase-1",
120
           "Example: -sbomid=13543 -rtagid=xxxx, for NZS Phase-1, compared against given release",
121
           "Example: -rtagid=2362, for Sydney R1/R2",
122
           "Example: -rtagid=8843 -root=StockholmSBOM",
123
           "Example: PackageName PackageVersion, for extracting a single package",
124
    )
125
}
126
 
127
#
128
#   Import essential EnvVars
129
#
130
EnvImport('GBE_DPKG');
131
 
5806 dpurdie 132
#
133
#   The extract option is special
134
#   It places the progam in a different mode
135
#
136
if ( $opt_extract )
137
{
138
    Error ("Cannot mix -extract with sbomid or rtagid" )
139
        if ( $opt_rtag_id || $opt_sbom_id || $#ARGV >= 0 );
140
 
141
    Error ("Cannot use -nopatch or -ignore with -extract")
142
        if ( ! $opt_patch || keys %ignore );
143
 
144
    Error ("S3 Recovery process must be run as buildadm")
145
        unless ($ENV{USER} eq 'buildadm');
146
 
147
    extract_files();
148
    exit (0);
149
}
150
 
151
 
152
Warning ("No sbomid provided. Output based an a Release") unless ( $opt_sbom_id );
153
$fpref = "release" unless ( $opt_sbom_id );
154
 
5708 dpurdie 155
if ( $opt_sbom_id )
156
{
157
    #
158
    #   Determines the OS_ID's for the bom
159
    #
160
    getOSIDforBOMID($opt_sbom_id);
161
    getSBOMDetails($opt_sbom_id);
162
 
163
    #
164
    #   Locate packages associated with the base install for each os
165
    #
166
    foreach my $base_env_id ( sort keys %os_env_list )
167
    {
168
        getPackagesforBaseInstall( $base_env_id );
169
    }
170
 
171
    #
172
    #   Determine all the top level packages in the BOM
173
    #
174
    foreach my $os_id ( sort keys %os_id_list )
175
    {
176
        getPackages_by_osid( $os_id );
177
    }
178
 
179
    #
180
    #   For each Top Level Package determine the dependent packages
181
    #
182
    getPkgDetailsForPVIDs (keys %pv_id);
183
    LocateStrays(0);
184
 
185
    #
186
    #   Determine packages in a given Release
187
    #
188
    if ( $opt_rtag_id )
189
    {
190
        getPkgDetailsByRTAG_ID( $opt_rtag_id );
191
    }
192
}
193
elsif ( $opt_rtag_id )
194
{
195
    getPkgDetailsByRTAG_ID( $opt_rtag_id );
196
    if ( $opt_rootpkg )
197
    {
198
        #
199
        #   Base the report on a single package in a release
200
        #   Determine the package
201
        #
202
        Error ("Root Package not found: $opt_rootpkg") unless ( exists $Release{$opt_rootpkg} );
203
        my @root_vers = keys %{$Release{$opt_rootpkg}};
204
        Error ("Multiple versions of Root Package: $opt_rootpkg", @root_vers ) if ( $#root_vers > 0 );
205
        $opt_rootpkg_version = $root_vers[0];
206
        Message("Root Package: $opt_rootpkg, " . $opt_rootpkg_version);
207
 
208
        getPkgDetailsByPV_ID( $Release{$opt_rootpkg}{$opt_rootpkg_version}{pv_id} );
209
    }
210
    else
211
    {
212
        getPkgDetailsForPVIDs (keys %Release_pvid);
213
    }
214
    LocateStrays(1);
215
}
216
elsif ( $#ARGV >= 1 )
217
{
218
    #
219
    #   Locate package and dependents
220
    #   Convert package name into a PVID
221
    #
222
    my $pv_id = getPkgDetailsByName( @ARGV );
223
    Error ("Cannot locate package by name and version: @ARGV")
224
        unless ( $pv_id );
225
 
226
    #
227
    #   Set package as the root package
228
    $opt_rootpkg = $ARGV[0];
229
    $opt_rootpkg_version = $ARGV[1];
230
    getPkgDetailsByPV_ID( $pv_id  );
231
    LocateStrays(2);
232
}
233
else
234
{
235
    Error ("Don't know what to do with common line arguments provided");
236
}
237
 
238
 
239
#
240
#   Remove packages to be ignored
241
#
242
foreach my $pkg ( keys %ignore )
243
{
244
    delete $Package{$pkg};
245
}
246
 
247
##
248
##   Display a list of all packages found so far
249
##
250
#foreach my $name ( sort keys %Package )
251
#{
252
#    foreach my $ver ( sort keys %{$Package{$name}} )
253
#    {
254
#
255
#        my $tag = $Package{$name}{$ver}{vcstag} || '';
256
#
257
#        printf ("%30s %15s %s\n", $name, $ver, $tag );
258
#    }
259
#}
260
 
261
#
262
#   Generate output files
263
#       1) Jats extract commands
264
#       2) Error list
265
my $file;
5806 dpurdie 266
$file = "${fpref}_missing.txt";
5708 dpurdie 267
push @create_list, $file;
268
open (JE, ">$file" ) || Error ("Cannot create $file");
269
 
5806 dpurdie 270
#$file = "${fpref}_status.txt";
271
#push @create_list, $file;
272
#
273
#open (ST, ">$file" ) || Error("Cannot create $file");
274
#print ST "Cannot build:\n";
5708 dpurdie 275
 
276
my $missing_count = 0;
277
my $pkg_count = 0;
278
foreach my $name ( sort keys %Package )
279
{
280
    foreach my $ver ( sort keys %{$Package{$name}} )
281
    {
282
       my $pdir = catdir($::GBE_DPKG, $name, $ver);
283
       my $tfile = catfile( $pdir, 'descpkg');
284
       $pkg_count++;
285
 
286
       if (! -d $pdir )
287
       {
288
           Warning("Not in dpkg_archive: $name $ver");
289
           $missing_count++;
5806 dpurdie 290
           print JE $name . '/' . $ver . "\n";
5708 dpurdie 291
           next;
292
       }
293
 
294
       if (! $tfile)
295
       {
296
           Warning("Not in dpkg_archive: $name $ver - Bad Form");
297
           $missing_count++;
5806 dpurdie 298
           print JE $name . '/' . $ver . "\n";
5708 dpurdie 299
           next;
300
       }
301
    }
302
}
303
 
304
Message("Packages: $pkg_count");
305
Message("Missing: $missing_count");
306
 
307
close (JE);
5806 dpurdie 308
#close (ST);
5708 dpurdie 309
 
310
 
311
#
312
#   Display names of files created
313
#
314
foreach my $file ( sort @create_list )
315
{
316
    Message ("Created: $file");
317
}
318
exit;
319
 
320
 
321
#-------------------------------------------------------------------------------
322
# Function        : getSBOMDetails
323
#
324
# Description     : Get some details about the SBOM
325
#                   Used fro descriptive text
326
#
327
# Inputs          : $bom_id             - BOM to process
328
#
329
# Returns         : 
330
#
331
sub getSBOMDetails
332
{
333
    my ($bom_id) = @_;
334
    my $foundDetails = 0;
335
    my (@row);
336
Verbose ("getSBOMDetails");
337
    connectDM(\$DM_DB) unless ($DM_DB);
338
 
339
    my $m_sqlstr = "SELECT distinct dp.PROJ_NAME ,bn.BOM_NAME, br.BRANCH_NAME, bm.BOM_VERSION, bm.BOM_LIFECYCLE" .
340
                   " FROM DEPLOYMENT_MANAGER.BOMS bm, DEPLOYMENT_MANAGER.BOM_NAMES bn, DEPLOYMENT_MANAGER.BRANCHES br, DEPLOYMENT_MANAGER.DM_PROJECTS dp" .
341
                   " WHERE bm.BOM_ID = $bom_id AND bm.BOM_NAME_ID = bn.BOM_NAME_ID AND bm.BRANCH_ID = br.BRANCH_ID AND br.PROJ_ID = dp.PROJ_ID";
342
 
343
    my $sth = $DM_DB->prepare($m_sqlstr);
344
    if ( defined($sth) )
345
    {
346
        if ( $sth->execute( ) )
347
        {
348
            if ( $sth->rows )
349
            {
350
                while ( @row = $sth->fetchrow_array )
351
                {
352
                    $sbom_project   = $row[0];
353
                    $sbom_name      = $row[1];
354
                    $sbom_branch    = $row[2];
355
                    $sbom_version   = $row[3] . '.' . $row[4];
356
                    $foundDetails = 1;
357
                }
358
            }
359
            $sth->finish();
360
        }
361
        else
362
        {
363
            Error("getSBOMDetails:Execute failure", $m_sqlstr );
364
        }
365
    }
366
    else
367
    {
368
        Error("getSBOMDetails:Prepare failure" );
369
    }
370
 
371
    Error("getSBOMDetails:No OS Information Found" ) unless $foundDetails;
372
 
373
}
374
 
375
#-------------------------------------------------------------------------------
376
# Function        : getReleaseDetails
377
#
378
# Description     : Get some details about the Release
379
#                   Used fro descriptive text
380
#
381
# Inputs          : $rtag_id             - RTAG_ID to process
382
#
383
# Returns         : 
384
#
385
sub getReleaseDetails
386
{
387
    my ($rtag_id) = @_;
388
    my $foundDetails = 0;
389
    my (@row);
390
Verbose ("getReleaseDetails");
391
    connectDM(\$DM_DB) unless ($DM_DB);
392
 
393
    my $m_sqlstr = "SELECT distinct rt.RTAG_NAME, pr.PROJ_NAME" .
394
                   " FROM RELEASE_MANAGER.RELEASE_TAGS rt, RELEASE_MANAGER.PROJECTS pr" .
395
                   " WHERE rt.RTAG_ID = $rtag_id AND rt.PROJ_ID = pr.PROJ_ID";
396
 
397
    my $sth = $DM_DB->prepare($m_sqlstr);
398
    if ( defined($sth) )
399
    {
400
        if ( $sth->execute( ) )
401
        {
402
            if ( $sth->rows )
403
            {
404
                while ( @row = $sth->fetchrow_array )
405
                {
406
                    $rtag_release = $row[0];
407
                    $rtag_project = $row[1];
408
                    $foundDetails = 1;
409
                }
410
            }
411
            $sth->finish();
412
        }
413
        else
414
        {
415
            Error("getReleaseDetails:Execute failure", $m_sqlstr );
416
        }
417
    }
418
    else
419
    {
420
        Error("getReleaseDetails:Prepare failure" );
421
    }
422
 
423
    Error("getReleaseDetails:No OS Information Found" ) unless $foundDetails;
424
 
425
}
426
 
427
 
428
 
429
#-------------------------------------------------------------------------------
430
# Function        : getOSIDforBOMID
431
#
432
# Description     : Get all the os_id's associated with a BOMID
433
#                   Also get base_env_id's where they exist
434
#
435
# Inputs          : $bom_id             - BOM to process
436
#
437
# Returns         :
438
#
439
 
440
sub getOSIDforBOMID
441
{
442
    my ($bom_id) = @_;
443
    my $foundDetails = 0;
444
    my (@row);
445
    Verbose ("getOSIDforBOMID");
446
    connectDM(\$DM_DB) unless ($DM_DB);
447
 
448
    my $m_sqlstr = qq{
449
                   SELECT distinct os.OS_ID, os.OS_NAME, nn.NODE_NAME, obe.BASE_ENV_ID 
450
                    FROM DEPLOYMENT_MANAGER.OPERATING_SYSTEMS os,
451
                         DEPLOYMENT_MANAGER.BOM_CONTENTS bc,
452
                         DEPLOYMENT_MANAGER.NETWORK_NODES nn,
453
                         DEPLOYMENT_MANAGER.OS_BASE_ENV obe
454
                    WHERE bc.BOM_ID = $bom_id
455
                      AND bc.NODE_ID = os.NODE_ID
456
                      AND nn.NODE_ID = os.NODE_ID
457
                      AND obe.OS_ID (+) = os.OS_ID
458
                      };
459
    my $sth = $DM_DB->prepare($m_sqlstr);
460
    if ( defined($sth) )
461
    {
462
        if ( $sth->execute( ) )
463
        {
464
            if ( $sth->rows )
465
            {
466
                while ( @row = $sth->fetchrow_array )
467
                {
468
                    Verbose ("OS_ID: ".join (',',@row) );
469
                    $os_id_list{$row[0]}{os_name} = $row[1];
470
                    $os_id_list{$row[0]}{node_name} = $row[2];
471
 
472
                    if ( defined $row[3] )
473
                    {
474
                        $os_env_list{$row[3]}{needed} = 1;
475
                        $os_env_list{$row[3]}{os_id}{$row[0]} = 1;
476
                    }
477
 
478
                    $foundDetails = 1;
479
                }
480
            }
481
            $sth->finish();
482
        }
483
        else
484
        {
485
            Error("getOSIDforBOMID:Execute failure" );
486
        }
487
    }
488
    else
489
    {
490
        Error("getOSIDforBOMID:Prepare failure" );
491
    }
492
 
493
    Error("getOSIDforBOMID:No OS Information Found" ) unless $foundDetails;
494
 
495
}
496
 
497
#-------------------------------------------------------------------------------
498
# Function        : getPackagesforBaseInstall
499
#
500
# Description     : Get all the packages for a given base install
501
#
502
# Inputs          :
503
#
504
# Returns         :
505
#
506
 
507
sub getPackagesforBaseInstall
508
{
509
    my ($base_env_id) = @_;
510
    my $foundDetails = 0;
511
    my (@row);
512
 
513
    connectDM(\$DM_DB) unless ($DM_DB);
514
 
515
    # First get details from pv_id
516
 
517
    my $m_sqlstr = "SELECT DISTINCT bec.PROD_ID, pkg.pkg_name, pv.pkg_version, pkg.pkg_id, pv.pv_id" .
518
                " FROM RELEASE_MANAGER.PACKAGES pkg, RELEASE_MANAGER.PACKAGE_VERSIONS pv, DEPLOYMENT_MANAGER.PRODUCT_DETAILS pd, DEPLOYMENT_MANAGER.BASE_ENV_CONTENTS bec".
519
                " WHERE bec.BASE_ENV_ID = $base_env_id AND bec.PROD_ID (+)= pv.PV_ID AND pv.pkg_id = pkg.pkg_id";
520
 
521
    my $sth = $DM_DB->prepare($m_sqlstr);
522
    if ( defined($sth) )
523
    {
524
        if ( $sth->execute( ) )
525
        {
526
            if ( $sth->rows )
527
            {
528
                while ( @row = $sth->fetchrow_array )
529
                {
530
                    Verbose ("OS ENV Package($base_env_id}:" . join (',',@row) );
531
 
532
                    my $pv_id =     $row[0];
533
                    my $name =      $row[1]  || 'BadName';
534
                    my $ver =       $row[2]  || 'BadVer';
535
 
536
                    $pv_id{$pv_id}{pkg_name} =$name;
537
                    $pv_id{$pv_id}{pkg_ver} = $ver;
538
                    foreach my $os_id ( keys %{$os_env_list{$base_env_id}{os_id}} )
539
                    {
540
                        $pv_id{$pv_id}{os_id}{$os_id} = 2;
541
                    }
542
                }
543
            }
544
            $sth->finish();
545
        }
546
        else
547
        {
548
            Error ("getPackagesforBaseInstall: Execute error");
549
        }
550
    }
551
    else
552
    {
553
        Error("getPackagesforBaseInstall:Prepare failure" );
554
    }
555
 
556
}
557
 
558
 
559
#-------------------------------------------------------------------------------
560
# Function        : getPackages_by_osid
561
#
562
# Description     : Get all the packages used by a given os_id
563
#
564
# Inputs          :
565
#
566
# Returns         :
567
#
568
 
569
my $count = 0;
570
sub getPackages_by_osid
571
{
572
    my ($os_id) =@_;
573
    my $foundDetails = 0;
574
    my (@row);
575
 
576
    connectDM(\$DM_DB) unless ($DM_DB);
577
 
578
    # First get details from pv_id
579
 
580
    my $m_sqlstr = "SELECT osc.*, pkg.pkg_name, pv.pkg_version, pd.IS_REJECTED, pv.IS_PATCH,pv.IS_OBSOLETE, pkg.pkg_id, pv.pv_id" .
581
                " FROM RELEASE_MANAGER.PACKAGES pkg, RELEASE_MANAGER.PACKAGE_VERSIONS pv, DEPLOYMENT_MANAGER.PRODUCT_DETAILS pd,".
582
                "(" .
583
                " SELECT osc.seq_num, osc.prod_id".
584
                " FROM DEPLOYMENT_MANAGER.os_contents osc".
585
                " WHERE osc.os_id = $os_id" .
586
                " ) osc" .
587
                " WHERE pd.PROD_ID (+)= pv.PV_ID" .
588
                "   AND pv.pkg_id = pkg.pkg_id" .
589
                "   AND osc.PROD_ID = pv.pv_id" .
590
                " ORDER BY osc.SEQ_NUM desc" ;
591
 
592
    my $sth = $DM_DB->prepare($m_sqlstr);
593
    if ( defined($sth) )
594
    {
595
        if ( $sth->execute( ) )
596
        {
597
            if ( $sth->rows )
598
            {
599
                while ( @row = $sth->fetchrow_array )
600
                {
601
next if ( $opt_test && ++$count > 2 );
602
                    Verbose ("SBOM Package:".join (',',@row) );
603
                    my $pv_id =     $row[8];
604
                    my $name =      $row[2]  || 'BadName';
605
                    my $ver =       $row[3]  || 'BadVer';
606
 
607
                    $pv_id{$pv_id}{pkg_name} =$name;
608
                    $pv_id{$pv_id}{pkg_ver} = $ver;
609
                    $pv_id{$pv_id}{os_id}{$os_id} = 1;
610
                }
611
            }
612
            $sth->finish();
613
        }
614
    }
615
    else
616
    {
617
        Error("getPackages_by_osid:Prepare failure" );
618
    }
619
}
620
 
621
#-------------------------------------------------------------------------------
622
# Function        : getPkgDetailsByPV_ID
623
#
624
# Description     : Populate the Packages structure given a PV_ID
625
#                   Called for each package in the SBOM
626
#
627
# Inputs          : PV_ID           - Package Unique Identifier
628
#
629
# Returns         : Populates Package
630
#
631
sub getPkgDetailsByPV_ID
632
{
633
    my ($PV_ID) = @_;
634
    my $foundDetails = 0;
635
    my (@row);
636
 
637
    connectRM(\$RM_DB) unless ($RM_DB);
638
 
639
    # First get details from pv_id
640
 
641
    my $m_sqlstr = "SELECT pv.PV_ID, pkg.PKG_NAME, pv.PKG_VERSION, pv.IS_DEPLOYABLE, pbi.BSA_ID, pbi.BM_ID, PV_DESCRIPTION, release_manager.PK_RMAPI.return_vcs_tag($PV_ID)" .
642
                    " FROM RELEASE_MANAGER.PACKAGE_VERSIONS pv, RELEASE_MANAGER.PACKAGES pkg, RELEASE_MANAGER.PACKAGE_BUILD_INFO pbi" .
643
                    " WHERE pv.PV_ID = \'$PV_ID\' AND pv.PKG_ID = pkg.PKG_ID AND pv.PV_ID = pbi.PV_ID (+) ";
644
 
645
    my $sth = $RM_DB->prepare($m_sqlstr);
646
    if ( defined($sth) )
647
    {
648
        if ( $sth->execute( ) )
649
        {
650
            if ( $sth->rows )
651
            {
652
                while ( @row = $sth->fetchrow_array )
653
                {
654
                    my $pv_id       = $row[0];
655
                    my $name        = $row[1];
656
                    my $ver         = $row[2];
657
                    my $deployable  = $row[3];
658
                    my $build_info  = $row[4] || '';
659
                    my $build_mach  = $row[5] || '';
660
                    my $description = $row[6] || '';
661
                    my $vcstag      = $row[7] || '';
662
 
663
                    #
664
                    #   BSA_ID: 1:debug, 2:prod, 3:debug+prod, 4:Java1.4 5: Java 1.5
665
                    #   BM_ID : 1:solaris, 2:win32, 3: linux, 4:generic
666
                    #
667
 
668
 
669
                    #
670
                    #   Does it look like a patch
671
                    #   We may want to ignore it.
672
                    #
673
                    my $patch = "";
674
                    unless ( $opt_patch )
675
                    {
676
                        if ( $ver =~ m~\.p\d+.\w+$~ )
677
                        {
678
                            $patch = "Patch";
679
                            $patch{$name} = 0
680
                                unless (  exists $patch{$name} );
681
                            $patch{$name}++;
682
                        }
683
                    }
684
                    Verbose ("getPkgDetailsByPV_ID: $PV_ID, $name, $ver, $build_mach ,$build_info, $patch");
685
                    next if ( $patch );
686
 
687
 
688
                    if ( exists $ignore{$name} )
689
                    {
690
                        Verbose2( "    Ignoring: $PV_ID, $name, $ver, $build_mach ,$build_info, $patch\n");
691
                        $ignore{$name}++;
692
                        last;
693
                    }
694
 
695
                    $vcstag =~ tr~\\/~/~;
696
 
697
                    $Package{$name}{$ver}{pvid} = $PV_ID;
698
                    $Package{$name}{$ver}{done} = 1;
699
                    $Package{$name}{$ver}{base} = 1;
700
                    $Package{$name}{$ver}{deployable} = 1 if ($deployable);
701
                    $Package{$name}{$ver}{build}{$build_mach} = $build_info if $build_mach;
702
                    $Package{$name}{$ver}{description} = $description;
703
                    $Package{$name}{$ver}{vcstag} = $vcstag;
704
 
705
                    GetDepends( $pv_id, $name, $ver );
706
 
707
                }
708
            }
709
            else
710
            {
711
                Warning ("No Package details for: PVID: $PV_ID");
712
            }
713
            $sth->finish();
714
        }
715
        else
716
        {
717
            Error("getPkgDetailsByPV_ID: Execute failure", $m_sqlstr );
718
        }
719
    }
720
    else
721
    {
722
        Error("Prepare failure" );
723
    }
724
}
725
 
726
#-------------------------------------------------------------------------------
727
# Function        : getPkgDetailsByName
728
#
729
# Description     : Determine the PVID for a given package name and version
730
#
731
# Inputs          : $pname          - Package name
732
#                   $pver           - Package Version
733
#
734
# Returns         : 
735
#
736
 
737
sub getPkgDetailsByName
738
{
739
    my ($pname, $pver) = @_;
740
    my $pv_id;
741
    my (@row);
742
 
743
    connectRM(\$RM_DB) unless ($RM_DB);
744
 
745
    # First get details for a given package version
746
 
747
    my $m_sqlstr = "SELECT pv.PV_ID, pkg.PKG_NAME, pv.PKG_VERSION" .
748
                    " FROM RELEASE_MANAGER.PACKAGE_VERSIONS pv, RELEASE_MANAGER.PACKAGES pkg" .
749
                    " WHERE pkg.PKG_NAME = \'$pname\' AND pv.PKG_VERSION = \'$pver\' AND pv.PKG_ID = pkg.PKG_ID";
750
    my $sth = $RM_DB->prepare($m_sqlstr);
751
    if ( defined($sth) )
752
    {
753
        if ( $sth->execute( ) )
754
        {
755
            if ( $sth->rows )
756
            {
757
                while ( @row = $sth->fetchrow_array )
758
                {
759
                    $pv_id = $row[0];
760
                    my $name = $row[1];
761
                    my $ver = $row[2];
762
                    Verbose( "getPkgDetailsByName :PV_ID= $pv_id");
763
                }
764
            }
765
            $sth->finish();
766
        }
767
    }
768
    else
769
    {
770
        Error("Prepare failure" );
771
    }
772
    return $pv_id;
773
}
774
 
775
#-------------------------------------------------------------------------------
776
# Function        : getPkgDetailsForPVIDs
777
#
778
# Description     : Get all package details by PVID, from a list of PVIDs
779
#
780
# Inputs          : List of PVID's to process
781
#
782
# Returns         : Nothing
783
#
784
sub getPkgDetailsForPVIDs
785
{
786
 
787
    my $count = 0;
788
    foreach my $pv_id ( @_ )
789
    {
790
        next if ( $opt_test && ++$count > 2 );
791
        getPkgDetailsByPV_ID( $pv_id);
792
    }
793
}
794
 
795
#-------------------------------------------------------------------------------
796
# Function        : GetDepends
797
#
798
# Description     : Extract the dependancies for a given package version
799
#                   Ignore pegged and SDK packages
800
#
801
# Inputs          : $pvid
802
#
803
# Returns         :
804
#
805
sub GetDepends
806
{
807
    my ($pv_id, $pname, $pver ) = @_;
808
 
809
    connectRM(\$RM_DB) unless ($RM_DB);
810
    if (exists $Pegged{$pv_id})
811
    {
812
        Verbose("$pname, $pver is pegged");
813
        return;
814
    }
815
 
816
    #
817
    #   Now extract the package dependacies
818
    #
819
    my $m_sqlstr = "SELECT pkg.PKG_NAME, pv.PKG_VERSION, pd.DPV_ID" .
820
                   " FROM RELEASE_MANAGER.PACKAGE_DEPENDENCIES pd, RELEASE_MANAGER.PACKAGE_VERSIONS pv, RELEASE_MANAGER.PACKAGES pkg" .
821
                   " WHERE pd.PV_ID = \'$pv_id\' AND pd.DPV_ID = pv.PV_ID AND pv.PKG_ID = pkg.PKG_ID";
822
    my $sth = $RM_DB->prepare($m_sqlstr);
823
    if ( defined($sth) )
824
    {
825
        if ( $sth->execute( ) )
826
        {
827
            if ( $sth->rows )
828
            {
829
                my %depends;
830
                while ( my @row = $sth->fetchrow_array )
831
                {
832
#print "$pname $pver ===== @row\n";
833
                    my $name = $row[0];
834
                    my $ver = $row[1];
835
 
836
                    Verbose2( "       Depends: $name, $ver");
837
 
838
                    $depends{$name,$ver} = 1;
839
                    $Package{$name}{$ver}{usedby}{$pname,$pver} = 1;
840
 
841
                    unless ( exists $Package{$name}{$ver}{done} )
842
                    {
843
                        my @DATA = ($name, $ver, $row[2]);
844
                        push @StrayPackages, \@DATA;
845
                    }
846
                }
847
                $Package{$pname}{$pver}{depends} = \%depends;
848
            }
849
            $sth->finish();
850
        }
851
    }
852
    else
853
    {
854
        Error("GetDepends:Prepare failure" );
855
    }
856
}
857
 
858
#-------------------------------------------------------------------------------
859
# Function        : getPkgDetailsByRTAG_ID
860
#
861
# Description     : Extract all the packages for a given rtag_id
862
#
863
# Inputs          : RTAG_ID
864
#
865
# Returns         : 
866
#
867
 
868
sub getPkgDetailsByRTAG_ID
869
{
870
    my ($RTAG_ID) = @_;
871
    my $foundDetails = 0;
872
    my (@row);
873
 
874
    connectRM(\$RM_DB);
875
 
876
    # First get details from pv_id
877
 
878
    my $m_sqlstr = "
879
                SELECT pv.PV_ID, 
880
                  pkg.PKG_NAME, 
881
                  pv.PKG_VERSION, 
882
                  rc.SDKTAG_ID, 
883
                  NVL2(peg.pv_id,1,0) as pegged 
884
                FROM RELEASE_MANAGER.RELEASE_CONTENT rc, 
885
                  RELEASE_MANAGER.PACKAGE_VERSIONS pv, 
886
                  RELEASE_MANAGER.PEGGED_VERSIONS peg, 
887
                  RELEASE_MANAGER.PACKAGES pkg 
888
                WHERE rc.RTAG_ID = $RTAG_ID 
889
                 AND rc.PV_ID     = pv.PV_ID 
890
                 AND pv.PKG_ID    = pkg.PKG_ID 
891
                 AND peg.RTAG_ID (+) = rc.RTAG_ID 
892
                 AND peg.PV_ID (+) = rc.pv_id
893
                ";
894
        $m_sqlstr=~ s~\s+~ ~g;
895
 
896
    my $sth = $RM_DB->prepare($m_sqlstr);
897
    if ( defined($sth) )
898
    {
899
        if ( $sth->execute( ) )
900
        {
901
            if ( $sth->rows )
902
            {
903
                while ( @row = $sth->fetchrow_array )
904
                {
905
                    my $pv_id   = $row[0];
906
                    my $name    = $row[1];
907
                    my $ver     = $row[2];
908
                    my $sdk     = $row[3] || 0;
909
                    my $peg     = $row[4];
910
                    Verbose ("getPkgDetailsByRTAG_ID: $RTAG_ID, $name, $ver, $pv_id, $sdk, $peg");
911
 
912
                    $Release{$name}{$ver}{pv_id} = $pv_id;
913
                    $Release_pvid{$pv_id} = 1;
914
                    $Pegged{$pv_id} = 1 if ($sdk | $peg);
915
                }
916
            }
917
            $sth->finish();
918
        }
919
        else
920
        {
921
            Error("Execute failure. getPkgDetailsByRTAG_ID: $m_sqlstr", $sth->errstr() );
922
 
923
        }
924
    }
925
    else
926
    {
927
        Error("getPkgDetailsByRTAG_ID:Prepare failure" );
928
    }
929
}
930
 
931
 
932
#-------------------------------------------------------------------------------
933
# Function        : LocateStrays
934
#
935
# Description     : Locate stray packages
936
#                   These are packages that have not been defined by the
937
#                   top level SBOM. These are not really stray
938
#
939
# Inputs          : $mode           2: No stray tagging
940
#                                   0: Mark all as stray
941
#                                   1: Don't mark packages as stray
942
#                                      if they are in releases hash
943
# Returns         : Nothing
944
#
945
sub LocateStrays
946
{
947
    my ($mode) = @_;
948
    while ( $#StrayPackages >= 0 )
949
    {
950
        my $DATA = pop @StrayPackages;
951
        my $name = $DATA->[0];
952
        my $ver = $DATA->[1];
953
        my $pv_id = $DATA->[2];
954
 
955
        next if ( exists $Package{$name}{$ver}{done} );
956
        getPkgDetailsByPV_ID ( $pv_id );
957
 
958
        next if ( $mode > 1 );
959
        if ( $mode )
960
        {
961
            next if ( exists $Release{$name}{$ver} );
962
        }
963
        $Package{$name}{$ver}{stray} = 1;
964
#print "Stray: $pv_id, $name, $ver\n";
965
    }
966
}
967
 
968
#-------------------------------------------------------------------------------
5806 dpurdie 969
# Function        : extract_files
970
#
971
# Description     : Alternate mode of operation
972
#                   Extract files from the generated list. This is intended to
973
#                   be run as a seperate phase taking the 'extract' file
974
#
975
# Inputs          :
976
#
977
# Returns         : 
978
#
979
sub extract_files
980
{
981
    my @extract_order;
982
    my %extract;
983
    ErrorConfig( 'name'    => 'CHECK-EXTRACT' );
984
 
985
    #
986
    #   Open the file and read in data in one hit
987
    #   Each line is <PkgName>/<PkgVersion>
988
    #
989
    Error ("Cannot find specified file: $opt_extract")
990
        unless ( -f $opt_extract );
991
 
992
    #
993
    #   Sanity test
994
    #
995
    my $tfile = 'sbin/getPkgFromS3.sh';
996
    Error("Cannot find expected utility: $tfile") unless (-f $tfile);
997
 
998
    $tfile = 'sbin/jats_quarantine.cnf';
999
    Error("Cannot find expected config file: $tfile") unless (-f $tfile);
1000
    ReadConfig($tfile);
1001
 
1002
    open (FH, "<$opt_extract" ) || Error ("Cannot open file");
1003
    while ( <FH> )
1004
    {
1005
        s~[\r\n]+$~~;
1006
        Verbose2 ($_);
1007
        next unless ( $_ );
1008
 
1009
        push @extract_order, $_;
1010
    }
1011
    close FH;
1012
 
1013
    #
1014
    #   Log the file processing
1015
    #
1016
    my $lfile = "${opt_extract}.log";
1017
    Message ("Creating logfile: ${opt_extract}.log");
1018
    open (FH, ">$lfile" ) || Error ("Cannot open log file: $lfile");
1019
 
1020
    #
1021
    #   Process each entry
1022
    #
1023
    foreach my $pv ( @extract_order )
1024
    {
1025
        if ( $opt_test )
1026
        {
1027
            Verbose ("$pv");
1028
            print FH "$pv : TEST\n";
1029
        }
1030
        else
1031
        {
1032
            my $rv = System ('sbin/getPkgFromS3.sh', "--bucket=$config{S3Bucket}", '-p', $::GBE_DPKG . '/' . $pv);
1033
            print FH "$pv : SUCCESS\n" unless $rv;
1034
            print FH "$pv : ERROR\n" if $rv;
1035
        }
1036
    }
1037
    close FH;
1038
    Message ("Results in logfile: ${opt_extract}.log");
1039
}
1040
 
1041
 
1042
#-------------------------------------------------------------------------------
1043
# Function        : ReadConfig
1044
#
1045
# Description     : Read in quarantine config file
1046
#                   Only used during extraction processing
1047
#
1048
# Inputs          : $cfile   - Config file to read
1049
#
1050
# Returns         : 
1051
#
1052
 
1053
sub ReadConfig
1054
{
1055
    my ($cfile) = @_;
1056
    open (CF, '<', $cfile ) || Error ("Connot open: $cfile");
1057
    while ( <CF> )
1058
    {
1059
        s~\s+$~~;
1060
        s~^\s+~~;
1061
        next if ( m~\s*#~ );        # Comment
1062
        next unless $_;             # Empty
1063
        if ( m~(.*?)\s*=\s*(.*)~ ) {
1064
            $config{$1} = $2;
1065
        }
1066
    }
1067
    close CF;
1068
 
1069
    #
1070
    # Check that I've got what I need
1071
    # 
1072
    foreach ( qw(S3Bucket S3Key S3Secret))
1073
    {
1074
        ReportError("Config Item not found: $_") unless defined $config{$_};
1075
    }
1076
    ErrorDoExit();
1077
 
1078
    #
1079
    #   Export the Secrets in EnvVars
1080
    #   Use program defaults so that we don't need to specify them
1081
    #   on the command line - for all to see
1082
    #
1083
    $ENV{AWSKEY} = $config{S3Key};
1084
    $ENV{AWSSECRET} = $config{S3Secret};
1085
}
1086
 
1087
#-------------------------------------------------------------------------------
5708 dpurdie 1088
#   Documentation
1089
#
1090
 
1091
=pod
1092
 
1093
=head1 NAME
1094
 
1095
checkRelease - Check Release/SBOM packages against dpkg_archive
1096
 
1097
=head1 SYNOPSIS
1098
 
6024 dpurdie 1099
  jats checkRelease [options] [name version]
5708 dpurdie 1100
 
1101
 Options:
6024 dpurdie 1102
    -help                   - brief help message
1103
    -help -help             - Detailed help message
1104
    -man                    - Full documentation
1105
    -sbomid=xxx             - Specify the SBOM to process
1106
    -rtagid=xxx             - Specify the Release to process (Optional)
1107
    -rootpackage=pkgName    - Specifies a root package. In conjunction with -rtagid.
1108
    -ignore=name            - Ignore packages with the specified name
1109
    -extract=fname          - Extract files from a previous run
1110
    -verbose                - Enable verbose output
1111
    -[no]patch              - Ignore/Include patches. Default:Include
1112
    -[no]test               - Reduced package scanning for test
5708 dpurdie 1113
 
1114
=head1 OPTIONS
1115
 
1116
=over 8
1117
 
1118
=item B<-help>
1119
 
1120
Print a brief help message and exits.
1121
 
1122
=item B<-help -help>
1123
 
1124
Print a detailed help message with an explanation for each option.
1125
 
1126
=item B<-man>
1127
 
1128
Prints the manual page and exits.
1129
 
1130
=item B<-sbomid=xxx>
1131
 
1132
This option specifies the SBOM to process. The sbomid must be determined from
1133
Deployment Manager.
1134
 
1135
=item B<-rtagid=xxx>
1136
 
1137
This option specified an RTAG_ID that must be determined from Release Manager.
1138
 
1139
This option may be used with or without the B<-sbomid=xxx> option.
1140
 
1141
With an SBOM_ID this option specifies an RTAG_ID to process in conjunction with the SBOM.
1142
The program will determine packages that are in the Release, but not in the
1143
SBOM.
1144
 
1145
Without an SBOM_ID, this option will limit the processing to the specified
1146
release. Less information is generated. This form of the generation may be
6024 dpurdie 1147
combined with B<-rootpackage=pkgName> to further limit the set of packages
5708 dpurdie 1148
processed.
1149
 
6024 dpurdie 1150
=item B<-rootpackage=pkgName>
5708 dpurdie 1151
 
1152
This option can be used in conjunction with B<-rtagid=xxx> to limit the
1153
extraction to named package and all of its dependent packages. The tool will
1154
determine the required version of the package via the specified release.
1155
 
1156
=item B<-ignore=name>
1157
 
1158
All versions of the named package will be ignored. This parameter is options.
1159
It may be used multiple times.
1160
 
5806 dpurdie 1161
=item B<-extract=name>
1162
 
1163
This option will process the 'extract' file created in a previous run of this
1164
program and restore missing package-versions as specified in the file.
1165
 
6024 dpurdie 1166
The command will then create a log file recording packages that could not be
5806 dpurdie 1167
extracted.
1168
 
6024 dpurdie 1169
This option does not interwork with many of the other command line options.
5806 dpurdie 1170
This option cannot be used in conjunction with the -rtagid, -sbomid, rootpackage
1171
and -nopatch.
1172
 
5708 dpurdie 1173
=item B<-[no]patch>
1174
 
1175
This option is used ignore patches. If -nopatch is selected, then packages
1176
versions that look like a patch will be added to the ignore list.
1177
 
1178
=item B<-[no]test>
1179
 
1180
This option is used for testing. It will only process the first two OS entries
1181
in the SBOM. This speeds up processing. It does not generate a complete list of
1182
packages.
1183
 
1184
=item B<-verbose>
1185
 
1186
This option will display progress information as the program executes.
1187
 
1188
=back
1189
 
1190
=head1 DESCRIPTION
1191
 
6024 dpurdie 1192
This program is a tool for recovering archived package from AWS S3 storage.
5708 dpurdie 1193
The program has two modes of operation:
1194
 
1195
=over 8
1196
 
1197
=item 1
1198
 
1199
Generation. Generate files describing packages within an SBOM/Release/
1200
Package.
1201
 
1202
=item 2
1203
 
6024 dpurdie 1204
Restoration.  Supervise restoration of packages from S3.
5708 dpurdie 1205
 
1206
=back
1207
 
6024 dpurdie 1208
=head2 Operations
5708 dpurdie 1209
 
1210
This program has several modes of operation. The mode is determined from the
1211
command line arguments provided.
1212
 
1213
=over 8
1214
 
6024 dpurdie 1215
=item   SBOM Restore
5708 dpurdie 1216
 
1217
This mode requires an SBOM_ID. If an RTAG_ID is also provided, then additional
1218
information will be generated.
1219
 
6024 dpurdie 1220
=item   Release Restore
5708 dpurdie 1221
 
6024 dpurdie 1222
If only an RTAG_ID is provided then the processing will be limited to the
5708 dpurdie 1223
packages involved in creating the specified release.
1224
 
1225
If a 'rootpackage' name is provided, then the processing is limited to
1226
packages that depend on the named package.
1227
 
6024 dpurdie 1228
=item   Single Package Restore
5708 dpurdie 1229
 
1230
If a package name and a package version are specified on the command line,
6024 dpurdie 1231
then the processing will be limited to the specified package and it's dependents.
5708 dpurdie 1232
No release related information will be provided.
1233
 
1234
=back
1235
 
6024 dpurdie 1236
The 'SBOM Restore' extract is the complete operation. All others are sub-sets of
5708 dpurdie 1237
this processing. The complete processing is:
1238
 
1239
=over 8
1240
 
1241
=item *
1242
 
1243
Determine all the NODES in the SBOM
1244
 
1245
=item *
1246
 
1247
Determine all the Base Packages for each NODE
1248
 
1249
=item *
1250
 
1251
Determine all the Packages for each NODE
1252
 
1253
=item *
1254
 
1255
Determine all the dependent packages for all packages encountered
1256
 
1257
=item *
1258
 
6024 dpurdie 1259
Generate a list of package-versions that are not present in dpkg_archive.
1260
These are 'missing'. This tools can be used in 'Restore' mode to restore these
1261
packages.
5708 dpurdie 1262
 
6024 dpurdie 1263
=back
5708 dpurdie 1264
 
6024 dpurdie 1265
This may take some time, as a typical SBOM may contain many hundreds of packages.
5708 dpurdie 1266
 
6024 dpurdie 1267
The program will display a list of files that have been created.
5708 dpurdie 1268
 
6024 dpurdie 1269
=head2 Restoration Operations
5708 dpurdie 1270
 
6024 dpurdie 1271
Given an 'missing' file from a previous run of this program the program will:
5708 dpurdie 1272
 
1273
=over 8
1274
 
1275
=item *
1276
 
6024 dpurdie 1277
Parse the 'missing' file
5708 dpurdie 1278
 
1279
=item *
1280
 
6024 dpurdie 1281
Copy the required package versions from AWS S3 and restore them into dpkg_archive.
5708 dpurdie 1282
 
6024 dpurdie 1283
If the S3 copies have been transferred to 'GLACIER", then a message will be displayed. The user will need to instigate
1284
the recovery from Glacier using traditional AWS tools. Currently this process is not automated by this tool.
5708 dpurdie 1285
 
1286
=item *
1287
 
6024 dpurdie 1288
Create a log file showing packages that could not be restored.
5708 dpurdie 1289
 
1290
=back
1291
 
6024 dpurdie 1292
The 'Restoration' operation can only be performed on the package server machine by the 'buildadm' user. 
1293
The operation is not available to other users.
5708 dpurdie 1294
 
6024 dpurdie 1295
=head2 Format of missing file
5708 dpurdie 1296
 
6024 dpurdie 1297
The 'missing' file is a file generated by this script in the 'Generation' mode and consumed by this script in the 'Restoration' mode.
5708 dpurdie 1298
 
6024 dpurdie 1299
The file can be manually created if required. The file has a simple format of:
5708 dpurdie 1300
 
1301
=over 8
1302
 
6024 dpurdie 1303
=item * One item per line
5708 dpurdie 1304
 
6024 dpurdie 1305
=item * Both Unix and Windows line terminators are supported
5708 dpurdie 1306
 
6024 dpurdie 1307
=item * There is no support for comments. All lines are processed
5708 dpurdie 1308
 
6024 dpurdie 1309
=item * Each line consists of the package name and the package version joined with a '/'.
5708 dpurdie 1310
 
6024 dpurdie 1311
=back
5708 dpurdie 1312
 
6024 dpurdie 1313
=head2 Example of missing file
5708 dpurdie 1314
 
6024 dpurdie 1315
A simple 'missing' file with two entries.
5708 dpurdie 1316
 
6024 dpurdie 1317
VIXubuntu1404LTS_VMcfg/1.0.0000.tool
1318
VIXubuntu1402LTS_VMcfg/1.0.0000.tool
1319
 
5708 dpurdie 1320
=cut
1321