File yup12.pl of Package yup
#!/usr/bin/perl -w
use strict;
use LWP;
use XML::Bare;
my $downloaddir='/abuild/meissner/yup/';
# from e.g. /etc/zypp/credentials.d/SCCcredentials
my $sccuser="";
my $sccpass="";
my @products = (
'SLES12_x86_64',
'SLES12_s390x',
'SLES12-SP1_x86_64',
'SLES12-SP2_x86_64',
'SLES12-SP2_RPI_aarch64',
'SLES12-SP3_x86_64',
'SLES12-SP4_x86_64',
'SDK12_x86_64',
'SDK12_s390x',
'SDK12-SP1_x86_64',
'SDK12-SP2_x86_64',
'SDK12-SP3_x86_64',
'SDK12-SP4_x86_64',
'PkgHub12-SP1_x86_64',
'PkgHub12-SP2_x86_64',
'PkgHub12-SP3_x86_64',
'PkgHub12-SP4_x86_64',
'ASMM12',
'LEGACY12_x86_64',
'LEGACY12_s390x',
'CERTIFICATIONS12_x86_64',
'WEBSCRIPT12_x86_64',
'WEBSCRIPT12_s390x',
'HAE_x86_64',
'HAE_s390x',
'HAE_GEO_x86_64',
'HAE_GEO_s390x',
'PUBLICCLOUD12_x86_64',
'PUBLICCLOUD12_s390x',
'HPC12_x86_64',
'CONTAINERS12_x86_64',
'TOOLCHAIN12_x86_64',
'SLEWE12',
'SLED12',
'SLED12-SP1',
);
# Change to 1 if you want to download the full released product GA trees aka "pool channels"
my $downloadpool = 0;
# Change to 1 if you want the debuginfo trees
my $downloaddebuginfo = 0;
# Debugging
my $debug = 0;
############# Internal ##############
my $ua = LWP::UserAgent->new;
$ua->agent("yup12/1.0 ");
$ua->credentials("scc.suse.com:443","SCC Connect API",$sccuser,$sccpass);
my %product2scc = (
'SLES12_x86_64' => 'https://scc.suse.com/access/services/1106?credentials=SUSE_Linux_Enterprise_Server_12_x86_64',
'SLES12_s390x' => 'https://scc.suse.com/access/services/1104?credentials=SUSE_Linux_Enterprise_Server_12_s390x',
'SLES12-SP1_x86_64' => 'https://scc.suse.com/access/services/1311?credentials=SUSE_Linux_Enterprise_Server_12_SP1_x86_64',
'SLES12-SP2_x86_64' => 'https://scc.suse.com/access/services/1346?credentials=SUSE_Linux_Enterprise_Server_12_SP2_x86_64',
'SLES12-SP2_RPI_aarch64'=> 'https://scc.suse.com/access/services/1403?credentials=SUSE_Linux_Enterprise_Server_for_the_Raspberry_Pi_12_SP2_aarch64',
'SLES12-SP3_x86_64' => 'https://scc.suse.com/access/services/1406?credentials=SUSE_Linux_Enterprise_Server_12_SP3_x86_64',
'SLES12-SP4_x86_64' => 'https://scc.suse.com/access/services/1610?credentials=SUSE_Linux_Enterprise_Server_12_SP4_x86_64',
'SDK12_x86_64' => 'https://scc.suse.com/access/services/1206?credentials=SUSE_Linux_Enterprise_Software_Development_Kit_12_x86_64',
'SDK12_s390x' => 'https://scc.suse.com/access/services/1136?credentials=SUSE_Linux_Enterprise_Software_Development_Kit_12_s390x',
'SDK12-SP1_x86_64' => 'https://scc.suse.com/access/services/1312?credentials=SUSE_Linux_Enterprise_Software_Development_Kit_12_x86_64',
'SDK12-SP2_x86_64' => 'https://scc.suse.com/access/services/1355?credentials=SUSE_Linux_Enterprise_Software_Development_Kit_12_x86_64',
'SDK12-SP3_x86_64' => 'https://scc.suse.com/access/services/1412?credentials=SUSE_Linux_Enterprise_Software_Development_Kit_12_SP3_x86_64',
'SDK12-SP4_x86_64' => 'https://scc.suse.com/access/services/1615?credentials=SUSE_Linux_Enterprise_Software_Development_Kit_12_SP4_x86_64',
'PkgHub12-SP1_x86_64' => 'https://scc.suse.com/access/services/1461?credentials=SUSE_Package_Hub_12_SP1_x86_64',
'PkgHub12-SP2_x86_64' => 'https://scc.suse.com/access/services/1464?credentials=SUSE_Package_Hub_12_SP2_x86_64',
'PkgHub12-SP3_x86_64' => 'https://scc.suse.com/access/services/1514?credentials=SUSE_Package_Hub_12_SP3_x86_64',
'PkgHub12-SP4_x86_64' => 'https://scc.suse.com/access/services/1798?credentials=SUSE_Package_Hub_12_SP4_x86_64',
'ASMM12' => 'https://scc.suse.com/access/services/1195?credentials=Advanced_Systems_Management_Module_12_x86_64',
'LEGACY12_x86_64' => 'https://scc.suse.com/access/services/1140?credentials=Legacy_Module_12_x86_64',
'LEGACY12_s390x' => 'https://scc.suse.com/access/services/1139?credentials=Legacy_Module_12_s390x',
'CERTIFICATIONS12_x86_64' => 'https://scc.suse.com/access/services/1357?credentials=Certifications_Module_12_x86_64',
'WEBSCRIPT12_x86_64' => 'https://scc.suse.com/access/services/1143?credentials=Web_and_Scripting_Module_12_x86_64',
'WEBSCRIPT12_s390x' => 'https://scc.suse.com/access/services/1142?credentials=Web_and_Scripting_Module_12_s390x',
'PUBLICCLOUD12_x86_64' => 'https://scc.suse.com/access/services/1203?credentials=Public_Cloud_Module_12_x86_64',
'PUBLICCLOUD12_s390x' => 'https://scc.suse.com/access/services/1202?credentials=Public_Cloud_Module_12_s390x',
'HPC12_x86_64' => 'https://scc.suse.com/access/services/1425?credentials=HPC_Module_12_x86_64',
'HAE_x86_64' => 'https://scc.suse.com/access/services/1241?credentials=SUSE_Linux_Enterprise_High_Availability_Extension_12_x86_64',
'HAE_s390x' => 'https://scc.suse.com/access/services/1240?credentials=SUSE_Linux_Enterprise_High_Availability_Extension_12_s390x',
'HAE_GEO_x86_64' => 'https://scc.suse.com/access/services/1147?credentials=SUSE_Linux_Enterprise_High_Availability_GEO_Extension_12_x86_64',
'HAE_GEO_s390x' => 'https://scc.suse.com/access/services/1146?credentials=SUSE_Linux_Enterprise_High_Availability_GEO_Extension_12_s390x',
'CONTAINERS12_x86_64' => 'https://scc.suse.com/access/services/1321?credentials=Containers_Module_12_x86_64',
'TOOLCHAIN12_x86_64' => 'https://scc.suse.com/access/services/1330?credentials=Toolchain_Module_12_x86_64',
# These are and will be x86_64 only for SLE12.
'SLEWE12' => 'https://scc.suse.com/access/services/1205?credentials=SUSE_Linux_Enterprise_Workstation_Extension_12_x86_64',
'SLED12' => 'https://scc.suse.com/access/services/1108?credentials=SUSE_Linux_Enterprise_Desktop_12_x86_64',
'SLED12-SP1' => 'https://scc.suse.com/access/services/1322?credentials=SUSE_Linux_Enterprise_Desktop_12_SP1_x86_64',
);
my $url;
my $req;
my $res;
sub download_file_checksum($$$$$$) {
my ($baseurl,$token,$alias,$file,$shatype,$checksumneeded) = @_;
if (($shatype ne "") && (-f "$downloaddir/$alias/$file")) {
open(CHECKSUM,"${shatype}sum <$downloaddir/$alias/$file|");
my $checksum = <CHECKSUM>;
close(CHECKSUM);
chomp $checksum;
$checksum =~ s/[ -]*$//;
if ($checksum eq $checksumneeded) {
print STDERR "$file - in cache with valid checksum.\n";
return 1;
}
print STDERR "$downloaddir/$alias/$file existing checksum mismatch: |$checksum| calculated vs |" . $checksumneeded . "| in repomd.xml\n";
unlink("$downloaddir/$alias/$file");
}
print "DOWNLOADING $file\n";
if ($file =~ /\//) {
my $dir = $file;
$dir =~ s/\/[^\/]*$//;
mkdir("$downloaddir/$alias/$dir");
}
$url = "$baseurl/$file?$token";
my $req = HTTP::Request->new(GET => $url);
my $res = $ua->request($req);
if (!$res->is_success) {
print STDERR "failed to download $url, reason " , $res->status_line, "\n";
return 0;
}
if (!open(CONTENT,">$downloaddir/$alias/$file")) {
warn "$downloaddir/$alias/$file:$!\n";
return 0;
}
print CONTENT $res->content;
close(CONTENT);
if ($checksumneeded ne "") {
open(CHECKSUM,"${shatype}sum <$downloaddir/$alias/$file|");
my $checksum = <CHECKSUM>;
close(CHECKSUM);
chomp $checksum;
$checksum =~ s/[ -]*$//;
if ($checksum ne $checksumneeded) {
print STDERR "$downloaddir/$alias/$file checksum mismatch: |$checksum| calculated vs |" . $checksumneeded . "| in repomd.xml\n";
unlink("$downloaddir/$alias/$file");
return 0;
}
}
return 1;
}
# we cannot use this as there is no checksum protection
sub download_updateinfo($$$$) {
my ($baseurl,$token,$alias,$text) = @_;
my $updatexml = new XML::Bare( text => $text );
my $updateroot = $updatexml->parse();
# will only work if we have more than 1 update ... EDONTCARE
if ("ARRAY" eq ref($updateroot->{'updates'}->{'update'})) {
for (my $u=0;defined($updateroot->{'updates'}->{'update'}->[$u]);$u++) {
my $update = $updateroot->{'updates'}->{'update'}->[$u];
if ("ARRAY" eq ref($update->{'pkglist'}->{'collection'}->{'package'})) {
for (my $p=0;defined($update->{'pkglist'}->{'collection'}->{'package'}->[$p]);$p++) {
my $package = $update->{'pkglist'}->{'collection'}->{'package'}->[$p];
# print "updateinfo filename " . $package->{'src'}->{'value'} . "\n";
}
} else {
my $package = $update->{'pkglist'}->{'collection'}->{'package'};
#print "updateinfo filename " . $package->{'src'}->{'value'} . "\n";
}
}
} else {
# channel with just 1 update
my $update = $updateroot->{'updates'}->{'update'};
if ("ARRAY" eq ref($update->{'pkglist'}->{'collection'}->{'package'})) {
for (my $p=0;defined($update->{'pkglist'}->{'collection'}->{'package'}->[$p]);$p++) {
my $package = $update->{'pkglist'}->{'collection'}->{'package'}->[$p];
# print "updateinfo filename " . $package->{'src'}->{'value'} . "\n";
}
} else {
my $package = $update->{'pkglist'}->{'collection'}->{'package'};
#print "updateinfo filename " . $package->{'src'}->{'value'} . "\n";
}
}
}
sub download_deltainfo($$$$) {
my ($baseurl,$token,$alias,$text) = @_;
my $deltaxml = new XML::Bare( text => $text );
my $deltaroot = $deltaxml->parse();
if ("ARRAY" eq ref($deltaroot->{'deltainfo'}->{'newpackage'})) {
for (my $di=0;defined($deltaroot->{'deltainfo'}->{'newpackage'}->[$di]);$di++) {
my $update = $deltaroot->{'deltainfo'}->{'newpackage'}->[$di];
# print STDERR "delta is " . ref($update->{'delta'}) . "\n";
if ("ARRAY" eq ref($update->{'delta'})) {
for (my $d=0;defined($update->{'delta'}->[$d]);$d++) {
my $package = $update->{'delta'}->[$d];
# print "filename " . $package->{'filename'}->{'value'} . "\n";
download_file_checksum($baseurl,$token,$alias,
$package->{'filename'}->{'value'},
$package->{'checksum'}->{'type'}->{'value'},
$package->{'checksum'}->{'value'}
);
}
} else {
my $package = $update->{'delta'};
# print "filename " . $package->{'filename'}->{'value'} . "\n";
download_file_checksum($baseurl,$token,$alias,
$package->{'filename'}->{'value'},
$package->{'checksum'}->{'type'}->{'value'},
$package->{'checksum'}->{'value'}
);
}
}
} else {
my $update = $deltaroot->{'deltainfo'}->{'newpackage'};
# print STDERR "delta is " . ref($update->{'delta'}) . "\n";
if ("ARRAY" eq ref($update->{'delta'})) {
for (my $d=0;defined($update->{'delta'}->[$d]);$d++) {
my $package = $update->{'delta'}->[$d];
# print "filename " . $package->{'filename'}->{'value'} . "\n";
download_file_checksum($baseurl,$token,$alias,
$package->{'filename'}->{'value'},
$package->{'checksum'}->{'type'}->{'value'},
$package->{'checksum'}->{'value'}
);
}
} else {
my $package = $update->{'delta'};
# print "filename " . $package->{'filename'}->{'value'} . "\n";
download_file_checksum($baseurl,$token,$alias,
$package->{'filename'}->{'value'},
$package->{'checksum'}->{'type'}->{'value'},
$package->{'checksum'}->{'value'}
);
}
}
}
sub download_primary($$$$) {
my ($baseurl,$token,$alias,$text) = @_;
my $packagexml = new XML::Bare( text => $text );
my $packageroot = $packagexml->parse();
# will only work if we have more than 1 update ... EDONTCARE
for (my $p=0;defined($packageroot->{'metadata'}->{'package'}->[$p]);$p++) {
my $package = $packageroot->{'metadata'}->{'package'}->[$p];
# print "filename " . $package->{'filename'}->{'value'} . "\n" if ($debug);
download_file_checksum($baseurl,$token,$alias,
$package->{'location'}->{'href'}->{'value'},
$package->{'checksum'}->{'type'}->{'value'},
$package->{'checksum'}->{'value'}
);
}
}
sub download_repodata($$) {
my ($downloadurl,$alias) = @_;
my ($baseurl,$token) = split(/\?/,$downloadurl);
print STDERR "$alias downloading $baseurl\n";
mkdir("$downloaddir/$alias");
mkdir("$downloaddir/$alias/repodata");
download_file_checksum($baseurl,$token,$alias,"repodata/repomd.xml.asc","","");
download_file_checksum($baseurl,$token,$alias,"repodata/repomd.xml.key","","");
return unless download_file_checksum($baseurl,$token,$alias,"repodata/repomd.xml","","");
my $repomdxml = new XML::Bare( file => "$downloaddir/$alias/repodata/repomd.xml");
my $reporoot = $repomdxml->parse();
for (my $j=0;defined($reporoot->{'repomd'}->{'data'}->[$j]);$j++) {
my $repodataxml = $reporoot->{'repomd'}->{'data'}->[$j];
my $type = $repodataxml->{'type'}->{'value'};
my $location = $repodataxml->{'location'}->{'href'}->{'value'};
# print STDERR "type = " . $type . "\n";
# print STDERR "location = " . $repodataxml->{'location'}->{'href'}->{'value'} . "\n";
# print STDERR "checksum = " . $repodataxml->{'checksum'}->{'value'} . "\n";
# print STDERR "checksum type = " . $repodataxml->{'checksum'}->{'type'}->{'value'} . "\n";
# print STDERR "timestamp = " . $repodataxml->{'timestamp'}->{'value'} . "\n";
# print STDERR "size = " . $repodataxml->{'size'}->{'value'} . "\n";
# print STDERR "open-size = " . $repodataxml->{'open-size'}->{'value'} . "\n";
# print STDERR "open-checksum = " . $repodataxml->{'open-checksum'}->{'value'} . "\n";
# <data type="susedata">
# <location href="repodata/a5b9125090f4487980e3bf94d469ae3a3c5c6e47016b18a0ddf26e9a7106bce7-susedata.xml.gz"/>
# <checksum type="sha256">a5b9125090f4487980e3bf94d469ae3a3c5c6e47016b18a0ddf26e9a7106bce7</checksum>
# <timestamp>1413282656</timestamp>
# <size>122</size>
# <open-size>123</open-size>
# <open-checksum type="sha256">743071394bef1495867b673ef088a678ce105740ee18b0cac194c5a267e1117d</open-checksum>
# </data>
# basic sanity
if ($location !~ /[a-z0-9\-.\/]/) {
print STDERR "bad character in location $location\n";
next;
}
next unless download_file_checksum($baseurl,$token,$alias,$location,
$repodataxml->{'checksum'}->{'type'}->{'value'},
$repodataxml->{'checksum'}->{'value'}
);
next if ($type eq "other");
next if ($type eq "susedata");
print STDERR "parsing type $type\n" if ($debug);
if ($location =~ /.gz$/) {
open(UNCOMPRESSED,"zcat $downloaddir/$alias/$location|")||die "zcat downloaddir/$alias/$location:$!";
} else {
open(UNCOMPRESSED,"<$downloaddir/$alias/$location");
}
my $text = join("",<UNCOMPRESSED>);
close(UNCOMPRESSED);
if ($type eq "updateinfo") {
download_updateinfo($baseurl,$token,$alias,$text);
next;
}
if ($type eq "deltainfo") {
download_deltainfo($baseurl,$token,$alias,$text);
next;
}
if ($type eq "primary") {
download_primary($baseurl,$token,$alias,$text);
next;
}
}
}
if (! -d $downloaddir) {
die "Download directory $downloaddir does not exist yet, please adjust directory and/or create it.\n";
}
foreach my $product (@products) {
if (!defined($product2scc{$product})) {
print STDERR "no scc url mapped for $product, check / adjust \%product2scc\n";
next;
}
$url = $product2scc{$product};
my $req = HTTP::Request->new(GET => $url);
my $res = $ua->request($req);
if (!$res->is_success) {
print STDERR "failed to download $url, reason " , $res->status_line, "\n";
next;
}
# print STDERR $res->content;
my $productxml = new XML::Bare( text => $res->content);
my $productroot = $productxml->parse();
for (my $i=0;defined($productroot->{'repoindex'}->{'repo'}->[$i]);$i++) {
my $repoxml = $productroot->{'repoindex'}->{'repo'}->[$i];
print STDERR "url = " . $repoxml->{'url'}->{'value'} . "\n" if ($debug);
print STDERR "alias = " . $repoxml->{'alias'}->{'value'} . "\n" if ($debug);
print STDERR "name = " . $repoxml->{'name'}->{'value'} . "\n" if ($debug);
print STDERR "autorefresh = " . $repoxml->{'autorefresh'}->{'value'} . "\n" if ($debug);
print STDERR "enabled = " . $repoxml->{'enabled'}->{'value'} . "\n" if ($debug);
print STDERR "distro_target = " . $repoxml->{'distro_target'}->{'value'} . "\n" if ($debug);
# <repo url="https://updates.suse.com/SUSE/Updates/SLE-SERVER/12/x86_64/update?5bc3650926e7f0c7ef485805725f135153d25d5137743176f0365397681adec894b25c0c6d9784d8d5c81258b2be6b675d80082e4457d838b355b45994851352e3767717c245c806d7fa1f071272021f90f6a865728b337161" alias="SLES12-Updates" name="SLES12-Updates" autorefresh="true" enabled="true" distro_target="sle-12-x86_64"/>
if ($repoxml->{'alias'}->{'value'} =~ /Pool/i && !$downloadpool) {
print "SKIP " . $repoxml->{'alias'}->{'value'} . " - pool channel not selected for downloading\n";
next;
}
if ($repoxml->{'alias'}->{'value'} =~ /debuginfo/i && !$downloaddebuginfo) {
print "SKIP " . $repoxml->{'alias'}->{'value'} . " - debuginfo channel not selected for downloading\n";
next;
}
download_repodata($repoxml->{'url'}->{'value'},$repoxml->{'alias'}->{'value'});
}
}