Subversion Repositories DevTools

Rev

Rev 341 | Rev 3987 | Go to most recent revision | Details | Compare with Previous | 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
 
361 dpurdie 447
=for htmltoc    DEPLOY::Update Release
448
 
341 dpurdie 449
=head1 NAME
450
 
451
jats_update_release - Extracts current package version list from Deployment Manager SBom(s)
452
                and copy resultant packages to release specific directory.
453
 
454
=head1 SYNOPSIS
455
 
456
  jats update_release -sbomid=xxx -rootdir=xxx [options]
457
 
458
 Options:
459
    -help              - brief help message
460
    -help -help        - Detailed help message
461
    -man               - Full documentation
462
    -sbomid=xxx        - Specify the Deployment Manager SBom(s) to process (Mandatory)
463
                       - Can be specified multiple times to combine SBoms
464
    -rootdir=xxx       - Specifies the root of the releases directory (Mandatory)
465
    -projectdir=xxx    - Override the project directory name that normally comes 
466
                       - from the Deployment Manager Project Name
467
    -releasedir=xxx    - Override the project release directory name that normally 
468
                       - comes from the Deployment Manager Project Release Name
469
    -filter=xxx        - Specifies a shell wildcard used to filter package files to copy
470
                       - Can be specified multiple times to use multiple filters
471
    -test              - Just log actions without copying files.
472
    -verbose           - Enable verbose output
473
 
474
=head1 OPTIONS
475
 
476
=over 8
477
 
478
=item B<-help>
479
 
480
Print a brief help message and exits.
481
 
482
=item B<-help -help>
483
 
484
Print a detailed help message with an explanation for each option.
485
 
486
=item B<-man>
487
 
488
Prints the manual page and exits.
489
 
490
=item B<-sbomid=xxx>
491
 
492
This option specifies one or more SBOM_ID's to use as the source of packages that will be copied.
493
The SBoms will be used to get a unique list of package/versions that can be copied from dpkg_archive.
494
 
495
This option is Mandatory and a minimum of one SBom must be supplied.  If more that one SBom is
496
supplied then all Sbom Ids must be of the same project and release with in that project.
497
 
498
=item B<-rootdir=xxx>
499
 
500
This option specifies the root directory where the packages will be copied to.
501
It is the top level directory in which the project/release directories will be created
502
and the packages copied to.
503
 
504
This option is mandatory and must specify a directory that exists.
505
 
506
=item B<-projectdir=xxx>
507
 
508
This option specifies the project directory that will be used in the rootdir for this release.
509
The project directory by default comes from the project name in Deployment Manager under which the 
510
SBom sbomid is under.
511
 
512
This option is provided to allow this script to be used against releases that are already 
513
populated and whose project directory does not match the Deployment Manager project name.
514
 
515
If the option is specified it must be used with the -releasedir option and must be a directory 
516
name that exists in the rootdir.
517
Additionally if used to populate a release then it must always be used to update the release.
518
 
519
=item B<-releasedir=xxx>
520
 
521
This option specifies the release directory that will be used in the projectdir for this release.
522
The release directory by default comes from the release name in Deployment Manager under 
523
which the SBom sbomid is under.
524
 
525
This option is provided to allow this script to be used against releases that are already 
526
populated and whose release directory does not match the Deployment Manager release name.
527
 
528
If the option is specified it must be used with the -projectdir option and must be a directory 
529
name that exists in the projectdir.
530
Additionally if used to populate a release then it must always be used to update the release.
531
 
532
=item B<-filter=xxx>
533
 
534
This option specifies a shell wildcard filter rule that is used to determine which files are
535
copied from package version directory in GBE_DPKG to the release directory.  This can be 
536
supplied multiple times to specify rules for copying.
537
 
538
This must be specified on the command line the first time this command is run against a release 
539
and packages are copied to the project/release directory.  These values are then written to a 
540
config file in the project/release directory so the same values can be used on subsequent runs.  
541
In these subsequent runs this option need not be specified as the config items will be used, however
542
they can be changed by specifying them again on the command line and the config will be re-written.
543
 
544
The values of these will depend on what builds are required for each project.  Some examples are
545
--filter='*-SOLARIS10_SPARC64-[DP].pkg.gz'
546
--filter='*-SOLARIS10_SPARC86-[DP].pkg.gz'
547
--filter='*-SOLARIS10_X64-[DP].pkg.gz'
548
--filter='*-SOLARIS10_X86-[DP].pkg.gz'
549
--filter='*-WIN32.exe'
550
 
551
=item B<-test>
552
 
553
This option will display what would be copied without actually copying anything
554
 
555
=item B<-verbose>
556
 
557
This option will display progress information as the program executes.
558
 
559
=back
560
 
561
=head1 DESCRIPTION
562
 
563
This program is used to update a projects release directory with the versions of
564
packages as indicated by the specified Deployment Manager SBoms.
565
 
566
Every invocation of this tool requires the -sbomid and -rootdir options specified.
567
 
568
The sbomid is used to get all the required information from Deployment Manager about
569
which package version are required, as well as the project name and release name under
570
which the Sboms are under.
571
 
572
The sbomid option can be specified multiple times to copy packages from multiple SBoms
573
to the Project Release directory.  All Sboms that are specified must be under the 
574
same Release under the same Project otherwise the script will abort.
575
 
576
The rootdir is used to specify the root location of the global releases directory.
577
This will be used as the root location from where the project and release specific
578
directories will be created to copy the files to.
579
 
580
By default the project and release names come from the project and release tree under
581
which the Sboms appear in Deployment Manager.  These values are used to populate the releasedir 
582
and projectdir respectively.
583
 
584
Alternatively you may override the projectdir and releasedir from Deployment Manager
585
by specifying the -projectdir=xxx and -releasedir=xxx options on the command line.
586
If they are used they must both be specified and must be valid directories of
587
rootdir/projectdir/releasedir.  These options are provided to allow existing release
588
directory structures to be used that don't match Deployment Managers project and release names.
589
 
590
The final release specific directory will be B<rootdir/projectdir/releasedir> and
591
all packages will be copied into this directory under a PkgName/PkgVersion directory tree.
592
 
593
For example running the command 
594
 
595
=over 8
596
 
597
=item jats updateRelease -sbomid=51904 -rootdir=/export/devl/releases
598
 
599
=back
600
 
601
will retrieve "BANGKOK (BKK)" as the project and "R1" as the release and will
602
copy packages into the "/export/devl/releases/BANGKOK (BKK)/R1" directory.
603
 
604
In addition to using Deployment Manager SBoms to determine which Package/Versions are
605
required to be copied this script also uses a set of shell wildcard filters that are
606
used to determine which files are actually copied when invoked.
607
 
608
The filter rules can be supplied on the command line if available read from a 
609
configuration file saved in the project/releasedir the last time the script was run
610
on this release directory.
611
 
612
One or more filter rules must be specified on the command line the first time this command 
613
is run against a project release directory.  These filter values are then written to a config
614
file in the project/release directory so the same values can be used on subsequent runs.  
615
In subsequent runs the filter rules will be loaded from the config file and need not be specified 
616
on the command line, however the filter rules in the config file can be changed by specifying 
617
them again on the command line and the config will be re-written.
618
 
619
=cut
620