Subversion Repositories DevTools

Rev

Rev 361 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
341 dpurdie 1
########################################################################
2
# Copyright ( C ) 2010 ERG Limited, All rights reserved
3
#
4
# Module name   : jats_update_release.pl
5
# Module type   : Makefile system
6
# Compiler(s)   : Perl
7
# Environment(s): jats build system
8
#
9
# Description   : Extracts current package version list from Deployment Manager
10
#                 SBom(s) and copies resultant packages to release specific
11
#                 directory.
12
#......................................................................#
13
 
14
require 5.008_002;
15
use File::Basename;
16
use File::Copy;
17
use File::Path;
18
use strict;
19
use warnings;
20
use JatsEnv;
21
use JatsError;
22
use JatsSystem;
23
use JatsRmApi;
24
use DBI;
25
use Getopt::Long;
26
use Pod::Usage;                             # required for help support
27
use Storable qw (dclone);
28
 
29
#
30
#   Config Options
31
#
32
my $VERSION = "1.0.0";                      # Update this
33
my $opt_help = 0;
34
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
35
my @opt_sbom_ids;
36
my $opt_rootdir;
37
my @opt_filters;
38
my $opt_projectdir;
39
my $opt_releasedir;
40
my $opt_test;
41
 
42
 
43
#
44
#   Constants
45
#
46
my $CONFFILE = ".updateRelease";
47
 
48
#
49
#   Data Base Interface
50
#
51
my $DM_DB;
52
 
53
 
54
#
55
#   The directory we copy to.
56
#
57
my $projectDestDir;
58
 
59
 
60
#
61
#   Configuration file vars
62
#
63
my @confFilters;
64
my $writeConf = 0;
65
 
66
 
67
# -------------------------------------------------------------------------
68
sub GetYesNo
69
#
70
# -------------------------------------------------------------------------
71
{
72
    my ($question) = @_;
73
    my ($u_tmp) = "";
74
    Question ("$question, (default: y) [y,n]: ");
75
 
76
    while ( <STDIN> )
77
    {
78
        $u_tmp = $_;
79
        chomp($u_tmp);
80
 
81
        return 1
82
            if ( "$u_tmp" eq "" );
83
 
84
        if( $u_tmp =~ /[yn]{1}/i )
85
        {
86
            return ( "$u_tmp" eq "y" );
87
        }
88
        else
89
        {
90
            Question("Please re-enter response? (default: y) [y,n]: ");
91
        }
92
    }
93
}
94
 
95
 
96
#==============================================================================
97
#   getSbomProjectAndRelease
98
#   Returns the Project Name and Release for supplied SBoms
99
#   Calls Error and exists on error condition
100
#==============================================================================
101
sub getSbomProjectAndRelease
102
{
103
    my ( $DB, $sboms ) = @_;
104
    my ( $bom, $proj, $rel, $lastProj, $lastRel );
105
 
106
    Error("getSbomProjectAndRelease: SBom Parameter Error, must pass array") if ( ref($sboms) ne "ARRAY" );
107
 
108
    # create a hash of sbom values so we can test after if any sboms could not be found
109
    my %sbomIdx = map { $_ => 1 } @{$sboms};
110
 
111
    my $m_sqlstr = "SELECT   boms.bom_id, dm_projects.proj_name, branches.branch_name " .
112
                   "FROM     deployment_manager.boms, deployment_manager.branches, deployment_manager.dm_projects " .
113
                   "WHERE    branches.branch_id = boms.branch_id AND " .
114
                   "         dm_projects.proj_id = branches.proj_id AND " .
115
                   "         boms.bom_id " . ( $#{$sboms} == 0 ? "= " . $sboms->[0] : "IN ( " . join(",", @{$sboms}) . ")" );
116
 
117
    my $sth = $DB->prepare($m_sqlstr);
118
    if ( defined($sth) )
119
    {
120
        if ( $sth->execute( ) )
121
        {
122
            if ( $sth->rows )
123
            {
124
                while ( ( $bom, $proj, $rel ) = $sth->fetchrow_array )
125
                {
126
                    if ( ! defined($proj) )
127
                    {
128
                        Error("getSbomProjectAndRelease: NULL Project Name from Deployment Manager Sbom : $bom");
129
                    }
130
                    elsif ( ! defined($rel) )
131
                    {
132
                        Error("getSbomProjectAndRelease: NULL Release Tag Name from Deployment Manager Sbom : $bom");
133
                    }
134
                    elsif ( defined($lastProj) && $proj ne $lastProj )
135
                    {
136
                        Error("getSbomProjectAndRelease: SBom Id [$bom] is in a different project [$proj]", "All SBom Id's must all be part of the same Deployment Manager Project");
137
                    }
138
                    elsif ( defined($lastRel) && $rel ne $lastRel )
139
                    {
140
                        Error("getSbomProjectAndRelease: SBom Id [$bom] is in a different project release [$rel]", "All SBom Id's must all be part of the same Deployment Manager Project Release");
141
                    }
142
                    $lastProj = $proj;
143
                    $lastRel  = $rel;
144
 
145
                    # delete sbom from idx, any remaining after loop will indicate we have an sbom that could not found
146
                    delete($sbomIdx{$bom});
147
                }
148
 
149
                my @sbomsNotFound = keys %sbomIdx;
150
                if ( $#sbomsNotFound > -1 )
151
                {
152
                    Error("getSbomProjectAndRelease: Could not find details for the following SBomId(s) " . join(",", @sbomsNotFound) );
153
                }
154
            }
155
            else
156
            {
157
                Error("getSbomProjectAndRelease: No SBom(s) found for Deployment Manager SBomId(s) " . join(",", @{$sboms}) );
158
            }
159
            $sth->finish();
160
        }
161
        else
162
        {
163
            Error("getSbomProjectAndRelease: Execute failure", $m_sqlstr );
164
        }
165
    }
166
    else
167
    {
168
        Error("getSbomProjectAndRelease: Prepare failure", $m_sqlstr );
169
    }
170
 
171
    return ( $lastProj, $lastRel );
172
}   # getSbomProjectAndRelease
173
 
174
 
175
#-------------------------------------------------------------------------------
176
# Function        : Main
177
#
178
# Description     : Main entry point
179
#                   Parse user options
180
#
181
# Inputs          :
182
#
183
# Returns         :
184
#
185
 
186
my $result = GetOptions (
187
                "help:+"            => \$opt_help,              # flag, multiple use allowed
188
                "manual:3"          => \$opt_help,              # flag, multiple use allowed
189
                "verbose:+"         => \$opt_verbose,           # flag
190
                "sbomid|sbom_id=s"  => \@opt_sbom_ids,          # multiple numbers
191
                "filter=s"          => \@opt_filters,           # multiple strings
192
                "rootdir=s"         => \$opt_rootdir,           # string
193
                "projectdir=s"      => \$opt_projectdir,        # string
194
                "releasedir=s"      => \$opt_releasedir,        # string
195
                "test"              => \$opt_test,              # flag
196
                );
197
 
198
#
199
#   Process help and manual options
200
#
201
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
202
pod2usage(-verbose => 1)  if ($opt_help == 2 );
203
pod2usage(-verbose => 2)  if ($opt_help > 2);
204
 
205
 
206
ErrorConfig( 'name'    => 'updateRelease',
207
             'verbose' => $opt_verbose );
208
 
209
#
210
#   Sanity tests
211
#
212
 
213
# Must supply at least one SbomId and the rootdir
214
if ( $#opt_sbom_ids == -1 || ! defined($opt_rootdir) )
215
{
216
    Error("Need -sbomid and -rootdir", "Example: -sbomid=2362 -rootdir=/export/devl/releases" ) ;
217
}
218
# Supplied rootdir must exists as a directory
219
elsif ( ! -d $opt_rootdir )
220
{
221
    Error("Root dir $opt_rootdir not a valid directory");
222
}
223
# Environment var GBE_DPKG must exists as a directory
224
elsif ( ! -d $ENV{GBE_DPKG} )
225
{
226
    Error("GBE_DPKG Environment var is not a directory") ;
227
}
228
# projectdir and releasedir must be specified together or not at all
229
elsif ( (  defined($opt_projectdir) && !defined($opt_releasedir) ) ||
230
        ( !defined($opt_projectdir) &&  defined($opt_releasedir) ) )
231
{
232
    Error("Both -projectdir and -releasedir are required if either one is specified") ;
233
}
234
# if projectdir is specified it must be a valid dir in the rootdir
235
elsif ( defined($opt_projectdir) && ! -d "$opt_rootdir/$opt_projectdir" )
236
{
237
    Error("The specified project directory does not exist in the root directory");
238
}
239
# if releasedir is specified it must be a valid dir in the projectdir
240
elsif ( defined($opt_releasedir) && ! -d "$opt_rootdir/$opt_projectdir/$opt_releasedir" )
241
{
242
    Error("The specified project/release directory does not exist in the root directory");
243
}
244
 
245
 
246
# Now lets connect and do our thing
247
connectRM(\$DM_DB);
248
 
249
 
250
if ( defined($opt_projectdir) && defined($opt_releasedir) )
251
{
252
    # If project and release dirs are specified we DONT need to get projectDir & releaseDir from DM but 
253
    # we do need to make sure that all sbomids specified have the same project & release in DM
254
    # so we call the getSbomProjectAndRelease but ignore the return values for project and release names
255
    getSbomProjectAndRelease($DM_DB, \@opt_sbom_ids);
256
}
257
else
258
{
259
    # If project and release dirs not specified then get the projectDir & releaseDir from DM and in addition 
260
    # we need to check that all sbomids specified have the same project & release in DM
261
    ( $opt_projectdir, $opt_releasedir ) = getSbomProjectAndRelease($DM_DB, \@opt_sbom_ids);
262
}
263
 
264
 
265
Message("Using Project [$opt_projectdir] Release [$opt_releasedir]");
266
 
267
# now set the projectDestDir 
268
$projectDestDir = "$opt_rootdir/$opt_projectdir/$opt_releasedir";
269
 
270
# load the config file if one exists
271
if ( -f "$projectDestDir/$CONFFILE" )
272
{
273
    Message("Loading release specific Config File");
274
 
275
    open(CONF, "<$projectDestDir/$CONFFILE") || Error("Failed to open config file");
276
    while( <CONF> )
277
    {
278
        chomp;
279
        if ( /^\s*filter\s*=\s*(.*)\s*$/ )
280
        {
281
            push(@confFilters, $1);
282
        }
283
    }
284
    close(CONF);
285
}
286
 
287
# validate config and command line options
288
if ( $#opt_filters > -1 && $#confFilters > -1 )
289
{
290
    Message("Filters supplied on Command line", @opt_filters);
291
    Message("Filters in release configuration file", @confFilters);
292
    if ( !GetYesNo("Replace Config Filters with command line Filters, be carefull as this may change the copy rules") )
293
    {
294
        Error("Script terminated by user.");
295
    }
296
    @confFilters = @opt_filters;
297
    $writeConf = 1;
298
}
299
elsif ( $#opt_filters > -1 && $#confFilters == -1 )
300
{
301
    Message("Filters supplied on Command line will be written to config file for release", @opt_filters);
302
    @confFilters = @opt_filters;
303
    $writeConf = 1;
304
}
305
elsif ( $#opt_filters == -1 && $#confFilters > -1 )
306
{
307
    Message("Filters loaded from config file for release will be used", @confFilters) if ( IsVerbose(1) );
308
}
309
elsif ( $#opt_filters == -1 && $#confFilters == -1 )
310
{
311
    Error("No Filters supplied on command line or release config file");
312
}
313
 
314
Message("Copying packages from $ENV{GBE_DPKG} to $projectDestDir");
315
 
316
if ( ! -d $projectDestDir )
317
{
318
    if ( defined($opt_test) )
319
    {
320
        Message("mkdir $projectDestDir");
321
    }
322
    else
323
    {
324
        eval { mkpath($projectDestDir) };
325
        Error("Failed to make project directory tree $projectDestDir") if ( $@ || ! -d $projectDestDir );
326
    }
327
}
328
 
329
my $m_sqlstr = "SELECT   packages.pkg_name, package_versions.pkg_version " .
330
               "FROM     deployment_manager.bom_contents, " .
331
               "         deployment_manager.network_nodes, " .
332
               "         deployment_manager.os_contents, " .
333
               "         deployment_manager.operating_systems, " .
334
               "         release_manager.package_versions, " .
335
               "         release_manager.packages " .
336
               "WHERE    network_nodes.node_id = bom_contents.node_id AND " .
337
               "         network_nodes.node_id = operating_systems.node_id AND " .
338
               "         operating_systems.os_id = os_contents.os_id AND " .
339
               "         os_contents.prod_id = package_versions.pv_id AND " .
340
               "         package_versions.pkg_id = packages.pkg_id AND " .
341
               "         bom_contents.bom_id " . ( $#opt_sbom_ids == 0 ? "= " . $opt_sbom_ids[0] : "IN ( " . join(",", @opt_sbom_ids) . ")" ) . " " .
342
               "GROUP BY packages.pkg_name, package_versions.pkg_version " .
343
               "ORDER BY packages.pkg_name ASC, package_versions.pkg_version ASC";
344
 
345
my ( $PKG_NAME, $PKG_VERSION );
346
 
347
my $sth = $DM_DB->prepare($m_sqlstr);
348
if ( defined($sth) )
349
{
350
    if ( $sth->execute( ) )
351
    {
352
        if ( $sth->rows )
353
        {
354
            while ( ( $PKG_NAME, $PKG_VERSION ) = $sth->fetchrow_array )
355
            {
356
                my $pkgDir = "$ENV{GBE_DPKG}/$PKG_NAME";
357
                my $srcDir = "$ENV{GBE_DPKG}/$PKG_NAME/$PKG_VERSION";
358
                my $dstDir = "$projectDestDir/$PKG_NAME/$PKG_VERSION";
359
 
360
                if ( -d "$srcDir" )
361
                {
362
                    my @filelist;
363
                    my $foundFiltered = 0;
364
 
365
                    # for each of the filter rules we glob the rule in the src pkg/version dir
366
                    # and if any of the globbed files dont exist in the dst dir add it to the 
367
                    # the filelist array of files to copy
368
                    foreach my $filter ( @confFilters )
369
                    {
370
                        foreach my $srcPath ( glob("$srcDir/$filter") )
371
                        {
372
                            $foundFiltered = 1;
373
                            my $srcFile = basename($srcPath);
374
                            push(@filelist, $srcFile) if ( ! -f "$dstDir/$srcFile" )
375
                        }
376
                    }
377
 
378
                    # if no files found using filters then issue warning
379
                    if ( $foundFiltered == 0 )
380
                    {
381
                        Warning("No Files found for Package Version $PKG_NAME/$PKG_VERSION using supplied filters");
382
                    }
383
                    #else we have found filtered files but they may already exist and if so filelist may be empty, so check it b4 doing anything
384
                    elsif ( $#filelist > -1 )
385
                    {
386
                        Message("Copying files for package $PKG_NAME version $PKG_VERSION");
387
                        if ( defined($opt_test) )
388
                        {
389
                            Message( map("$_...", @filelist) );
390
                        }
391
                        else
392
                        {
393
                            eval { mkpath($dstDir) };
394
                            Error("Failed to make destination directory") if ( $@ || ! -d $dstDir );
395
                            foreach my $file ( @filelist )
396
                            {
397
                                Verbose("$file...");
398
                                if ( ! copy("$srcDir/$file", $dstDir) )
399
                                {
400
                                    Warning("Failed to copy $file ($!)");
401
                                }
402
                            }
403
                        }
404
                    }
405
                }
406
                elsif ( ! -d "$pkgDir" )
407
                {
408
                    # if srcDir and pkgDir dont exist then package is not in dpkg_archive so display message
409
                    Verbose("Skipping Package $PKG_NAME as it does not exist in dpkg_archive");
410
                }
411
                else
412
                {
413
                    # However if srcDir does not exist but pkgDir does exist then the package version is missing which maybe an issue
414
                    Warning("Missing Version $PKG_VERSION for Package $PKG_NAME in dpkg_archive");
415
                }
416
            }
417
        }
418
        else
419
        {
420
            Error("No Boms found for Deployment Manager SBomId(s) " . join(",", @opt_sbom_ids) );
421
        }
422
        $sth->finish();
423
    }
424
    else
425
    {
426
        Error("Execute failure", $m_sqlstr );
427
    }
428
}
429
else
430
{
431
    Error("Prepare failure", $m_sqlstr );
432
}
433
 
434
if ( ! defined($opt_test) && $writeConf )
435
{
436
    open(CONF, ">$projectDestDir/$CONFFILE") || Error("Failed to open config file");
437
    print CONF map( "filter=$_\n", @confFilters);
438
    close CONF;
439
}
440
 
441
#-------------------------------------------------------------------------------
442
#   Documentation
443
#
444
 
445
=pod
446
 
447
=head1 NAME
448
 
449
jats_update_release - Extracts current package version list from Deployment Manager SBom(s)
450
                and copy resultant packages to release specific directory.
451
 
452
=head1 SYNOPSIS
453
 
454
  jats update_release -sbomid=xxx -rootdir=xxx [options]
455
 
456
 Options:
457
    -help              - brief help message
458
    -help -help        - Detailed help message
459
    -man               - Full documentation
460
    -sbomid=xxx        - Specify the Deployment Manager SBom(s) to process (Mandatory)
461
                       - Can be specified multiple times to combine SBoms
462
    -rootdir=xxx       - Specifies the root of the releases directory (Mandatory)
463
    -projectdir=xxx    - Override the project directory name that normally comes 
464
                       - from the Deployment Manager Project Name
465
    -releasedir=xxx    - Override the project release directory name that normally 
466
                       - comes from the Deployment Manager Project Release Name
467
    -filter=xxx        - Specifies a shell wildcard used to filter package files to copy
468
                       - Can be specified multiple times to use multiple filters
469
    -test              - Just log actions without copying files.
470
    -verbose           - Enable verbose output
471
 
472
=head1 OPTIONS
473
 
474
=over 8
475
 
476
=item B<-help>
477
 
478
Print a brief help message and exits.
479
 
480
=item B<-help -help>
481
 
482
Print a detailed help message with an explanation for each option.
483
 
484
=item B<-man>
485
 
486
Prints the manual page and exits.
487
 
488
=item B<-sbomid=xxx>
489
 
490
This option specifies one or more SBOM_ID's to use as the source of packages that will be copied.
491
The SBoms will be used to get a unique list of package/versions that can be copied from dpkg_archive.
492
 
493
This option is Mandatory and a minimum of one SBom must be supplied.  If more that one SBom is
494
supplied then all Sbom Ids must be of the same project and release with in that project.
495
 
496
=item B<-rootdir=xxx>
497
 
498
This option specifies the root directory where the packages will be copied to.
499
It is the top level directory in which the project/release directories will be created
500
and the packages copied to.
501
 
502
This option is mandatory and must specify a directory that exists.
503
 
504
=item B<-projectdir=xxx>
505
 
506
This option specifies the project directory that will be used in the rootdir for this release.
507
The project directory by default comes from the project name in Deployment Manager under which the 
508
SBom sbomid is under.
509
 
510
This option is provided to allow this script to be used against releases that are already 
511
populated and whose project directory does not match the Deployment Manager project name.
512
 
513
If the option is specified it must be used with the -releasedir option and must be a directory 
514
name that exists in the rootdir.
515
Additionally if used to populate a release then it must always be used to update the release.
516
 
517
=item B<-releasedir=xxx>
518
 
519
This option specifies the release directory that will be used in the projectdir for this release.
520
The release directory by default comes from the release name in Deployment Manager under 
521
which the SBom sbomid is under.
522
 
523
This option is provided to allow this script to be used against releases that are already 
524
populated and whose release directory does not match the Deployment Manager release name.
525
 
526
If the option is specified it must be used with the -projectdir option and must be a directory 
527
name that exists in the projectdir.
528
Additionally if used to populate a release then it must always be used to update the release.
529
 
530
=item B<-filter=xxx>
531
 
532
This option specifies a shell wildcard filter rule that is used to determine which files are
533
copied from package version directory in GBE_DPKG to the release directory.  This can be 
534
supplied multiple times to specify rules for copying.
535
 
536
This must be specified on the command line the first time this command is run against a release 
537
and packages are copied to the project/release directory.  These values are then written to a 
538
config file in the project/release directory so the same values can be used on subsequent runs.  
539
In these subsequent runs this option need not be specified as the config items will be used, however
540
they can be changed by specifying them again on the command line and the config will be re-written.
541
 
542
The values of these will depend on what builds are required for each project.  Some examples are
543
--filter='*-SOLARIS10_SPARC64-[DP].pkg.gz'
544
--filter='*-SOLARIS10_SPARC86-[DP].pkg.gz'
545
--filter='*-SOLARIS10_X64-[DP].pkg.gz'
546
--filter='*-SOLARIS10_X86-[DP].pkg.gz'
547
--filter='*-WIN32.exe'
548
 
549
=item B<-test>
550
 
551
This option will display what would be copied without actually copying anything
552
 
553
=item B<-verbose>
554
 
555
This option will display progress information as the program executes.
556
 
557
=back
558
 
559
=head1 DESCRIPTION
560
 
561
This program is used to update a projects release directory with the versions of
562
packages as indicated by the specified Deployment Manager SBoms.
563
 
564
Every invocation of this tool requires the -sbomid and -rootdir options specified.
565
 
566
The sbomid is used to get all the required information from Deployment Manager about
567
which package version are required, as well as the project name and release name under
568
which the Sboms are under.
569
 
570
The sbomid option can be specified multiple times to copy packages from multiple SBoms
571
to the Project Release directory.  All Sboms that are specified must be under the 
572
same Release under the same Project otherwise the script will abort.
573
 
574
The rootdir is used to specify the root location of the global releases directory.
575
This will be used as the root location from where the project and release specific
576
directories will be created to copy the files to.
577
 
578
By default the project and release names come from the project and release tree under
579
which the Sboms appear in Deployment Manager.  These values are used to populate the releasedir 
580
and projectdir respectively.
581
 
582
Alternatively you may override the projectdir and releasedir from Deployment Manager
583
by specifying the -projectdir=xxx and -releasedir=xxx options on the command line.
584
If they are used they must both be specified and must be valid directories of
585
rootdir/projectdir/releasedir.  These options are provided to allow existing release
586
directory structures to be used that don't match Deployment Managers project and release names.
587
 
588
The final release specific directory will be B<rootdir/projectdir/releasedir> and
589
all packages will be copied into this directory under a PkgName/PkgVersion directory tree.
590
 
591
For example running the command 
592
 
593
=over 8
594
 
595
=item jats updateRelease -sbomid=51904 -rootdir=/export/devl/releases
596
 
597
=back
598
 
599
will retrieve "BANGKOK (BKK)" as the project and "R1" as the release and will
600
copy packages into the "/export/devl/releases/BANGKOK (BKK)/R1" directory.
601
 
602
In addition to using Deployment Manager SBoms to determine which Package/Versions are
603
required to be copied this script also uses a set of shell wildcard filters that are
604
used to determine which files are actually copied when invoked.
605
 
606
The filter rules can be supplied on the command line if available read from a 
607
configuration file saved in the project/releasedir the last time the script was run
608
on this release directory.
609
 
610
One or more filter rules must be specified on the command line the first time this command 
611
is run against a project release directory.  These filter values are then written to a config
612
file in the project/release directory so the same values can be used on subsequent runs.  
613
In subsequent runs the filter rules will be loaded from the config file and need not be specified 
614
on the command line, however the filter rules in the config file can be changed by specifying 
615
them again on the command line and the config will be re-written.
616
 
617
=cut
618