#!/usr/bin/perl -w
#
# Imports the product lifecycle map from AIMAS
#
# Has local overrides / supplements were aimaas data is incomplete or incorrect

# smelt lists all products: https://smelt.suse.de/api/v1/basic/products/ 

use strict;

use JSON;
use Data::Dumper;
use LWP;
use LWP::UserAgent;

# "Productname" -> time
%Products::product2endofgeneral = (
	"SUSE Linux Enterprise Server 11 SP1" => "2012-08-31",
	"SUSE Linux Enterprise Server 11 SP3-LTSS" => "2016-01-31",
	"SUSE Linux Enterprise Server for SAP Applications 11 SP4" => "2019-03-31",
	"SUSE Linux Enterprise Server ESPOS 12 SP4" => "2020-06-30",
);

# "Productname" -> time
%Products::product2endofltss = (
	"SUSE Linux Enterprise Server 11 SP1" => "2015-08-31",
	"SUSE Linux Enterprise Server 11 SP3-LTSS" => "2019-01-31",
	"SUSE Linux Enterprise Server for SAP Applications 11 SP4" => "2022-03-31",
);

# Table has some local overrides for now, until its fixed in aimas.
# "Productname" -> "generalsupport", "ltss", "eol", "development"

%Products::product2state = (
	"SLE_9_SP3-TERADATA"	=> "eol",
	"SLE-9-SP4"		=> "eol",
	"SLE-10-SP2"		=> "eol",
	"SLES-10-SP3"		=> "eol",
	"SLE-10-SP3-MANAGER"	=> "eol",
	"SLES-10-SP4"		=> "eol",
	"SLED-10-SP3"		=> "eol",
	"SLES_LTSS-10-SP4"	=> "eol",
	"SLED-10-SP4"		=> "eol",
	"openSUSE-11.4"		=> "eol",
	"SLES-LTSS-ERICSSON 12 SP2" => "eol",
	"SLES-LTSS-SAP 12 SP2"	=> "eol",

	"SUSE Linux Enterprise High Performance Computing 12" => "generalsupport",
	"SUSE Linux Enterprise Micro for Rancher 5.2" => "generalsupport",

	"SUSE Linux Enterprise Server 15 SP3-BCL" => "eol",
	"SUSE Linux Enterprise Desktop 15 SP4 LTSS" => "ltss",

	"SUSE Linux Enterprise Server 11" => "eol",
	"SUSE Linux Enterprise Server 11 SP1" => "eol",
	"SUSE Linux Enterprise Server 11 SP1 LTSS" => "eol",
	"SUSE Linux Enterprise Server 11 SP1-LTSS" => "eol",
	"SUSE Linux Enterprise Server 11 SP2" => "eol",
	"SUSE Linux Enterprise Server 11 SP2 LTSS" => "eol",
	"SUSE Linux Enterprise Server 11 SP2-LTSS" => "eol",
	"SUSE Linux Enterprise Server 11 SP3-LTSS" => "eol",
	"SUSE Linux Enterprise Server 11 SP3 LTSS" => "eol",
	"Security Module for SUSE Linux Enterprise 11" => "eol",
	"Public Cloud Module for SUSE Linux Enterprise 11" => "eol",

	"SUSE CaaS Platform Toolchain 3" => "eol",

	"HPE Helion OpenStack Cloud 8" => "eol",	# named "HPE Helion OpenStack 8" in SCC

	"SUSE Linux Enterprise Server for SAP Applications 11" => "eol",
	"SUSE Linux Enterprise Server for SAP Applications 11 SP1" => "eol",
	"SUSE Linux Enterprise Server for SAP Applications 11 SP2" => "eol",
	"SUSE Linux Enterprise Server for SAP Applications 11 SP3" => "eol",
	"SUSE Linux Enterprise Server for SAP Applications 11 SP4" => "eol",
	"SUSE Linux Enterprise Server for SAP Business All-in-One 11 SP1" => "eol",
	"SUSE Linux Enterprise Enterprise Server 11 SP1 for SAP Enterprise Search" => "eol",
	"SUSE Lifecycle Management Server 1.3" => "eol",
	"SLES for SAP Applications 11 SP2" => "eol",
	"SLES for SAP Applications 11 SP3" => "eol",
	"WebYaST for SLE-11" => "eol",
	"SUSE WebYast 1.3" => "eol",
	"SUSE Studio Extension for System z 1.2" => "eol",
	"SUSE Studio Onsite Runner 1.3" => "eol",

	"Magnum Orchestration 7" => "eol",
	"SUSE Linux Enterprise Server for the Raspberry Pi 12 SP2" => "eol",

	"SUSE Linux Enterprise Point of Sale 12 SP2" => "eol",

	"SUSE Manager 2.1" => "eol",
	"SUSE Manager Proxy 1.2" => "eol",
	"SUSE Manager Proxy 1.7" => "eol",
	"SUSE Manager Proxy 2.1" => "eol",
	"SUSE Manager Server 1.2" => "eol",
	"SUSE Manager Server 1.7" => "eol",
	"SUSE Manager Server 2.1" => "eol",

	"SUSE OpenStack Cloud 5" => "eol",
	"SUSE Linux Enterprise Point of Service Image Server 12 SP2" => "eol",

	"SUSE Cloud 2.0" => "eol",
	"SUSE Cloud 3" => "eol",
	"SUSE Cloud 4" => "eol",
	"SUSE Cloud 4 Dependencies" => "eol",
	"SUSE Cloud 5" => "eol",

	"SUSE Studio Onsite 1.3" => "eol",
	"SUSE Linux Enterprise Point of Service 11 SP2" => "eol",
	"SUSE Linux Enterprise Point of Sale 12 SP2-CLIENT" => "eol",

	"SLES15-EC2-CHOST-HVM-BYOS" => "ltss",
	"SLES15-SP1-CHOST-BYOS-Azure" => "ltss",
	"SLES15-SP1-CHOST-BYOS-EC2" => "ltss",
	"SLES15-SP1-CHOST-BYOS-GCE" => "ltss",
	"SLES15-SP2-CHOST-BYOS-Aliyun" => "ltss",
	"SLES15-SP2-CHOST-BYOS-Azure" => "ltss",
	"SLES15-SP2-CHOST-BYOS-EC2" => "ltss",
	"SLES15-SP2-CHOST-BYOS-GCE" => "ltss",
	"SLES15-SP3-CHOST-BYOS-Aliyun" => "ltss",
	"SLES15-SP3-CHOST-BYOS-Azure" => "ltss",
	"SLES15-SP3-CHOST-BYOS-EC2" => "ltss",
	"SLES15-SP3-CHOST-BYOS-GCE" => "ltss",
	"SLES15-SP3-CHOST-BYOS-SAP-CCloud" => "ltss",
	"SLES15-SP4-CHOST-BYOS" => "ltss",
	"SLES15-SP4-CHOST-BYOS-Aliyun" => "ltss",
	"SLES15-SP4-CHOST-BYOS-Azure" => "ltss",
	"SLES15-SP4-CHOST-BYOS-EC2" => "ltss",
	"SLES15-SP4-CHOST-BYOS-GCE" => "ltss",
	"SLES15-SP4-CHOST-BYOS-SAP-CCloud" => "ltss",
	"SLES15-SP5-CHOST-BYOS" => "generalsupport",
	"SLES15-SP5-CHOST-BYOS-Aliyun" => "generalsupport",
	"SLES15-SP5-CHOST-BYOS-Azure" => "generalsupport",
	"SLES15-SP5-CHOST-BYOS-EC2" => "generalsupport",
	"SLES15-SP5-CHOST-BYOS-GCE" => "generalsupport",
	"SLES15-SP5-CHOST-BYOS-SAP-CCloud" => "generalsupport",
	"SLES15-SP6-CHOST-BYOS" => "generalsupport",
	"SLES15-SP6-CHOST-BYOS-Aliyun" => "generalsupport",
	"SLES15-SP6-CHOST-BYOS-Azure" => "generalsupport",
	"SLES15-SP6-CHOST-BYOS-EC2" => "generalsupport",
	"SLES15-SP6-CHOST-BYOS-GCE" => "generalsupport",
	"SLES15-SP6-CHOST-BYOS-SAP-CCloud" => "generalsupport",
	"SLES15-SP6-CHOST-BYOS-GDC" => "generalsupport",

	"SUSE Linux Enterprise Point of Sale 11 SP3" => "eol",
	"SUSE Linux Enterprise Point of Service 11 SP3" => "eol",
	"SUSE Linux Enterprise Real Time 11 SP3" => "eol",
	"SUSE Linux Enterprise Real Time 11 SP4" => "eol",
	"SUSE Linux Enterprise Real Time 12 SP1" => "eol",
	"SUSE Linux Enterprise Server 11 SP4 LTSS" => "eol",
	"SUSE Linux Enterprise Server 15 SP1-BCL" => "eol",
	"SUSE Linux Enterprise Server 15 SP2-BCL" => "eol",
	"SUSE Linux Enterprise Server 15-ESPOS" => "ltss",
	"SUSE Linux Enterprise Server Business Critical Linux 15 SP1" => "ltss",
	"SUSE Linux Enterprise Server Business Critical Linux 15 SP2" => "ltss",
	"SUSE Linux Enterprise Server for Raspberry Pi 12 SP2" => "eol",
	"SUSE Linux Enterprise Module for Package Hub 15" => "eol",
	"SUSE Linux Enterprise Module for Package Hub 15 SP1" => "eol",
	"SUSE Linux Enterprise Module for Package Hub 15 SP2" => "eol",
	"SUSE Linux Enterprise Module for Package Hub 15 SP3" => "eol",
	"SUSE Linux Enterprise Module for Package Hub 15 SP4" => "eol",
	"SUSE Linux Enterprise Module for Package Hub 15 SP5" => "generalsupport",
	"SUSE Linux Enterprise Module for Package Hub 15 SP6" => "generalsupport",
	"SUSE Linux Enterprise Server Business Critical Linux 15 SP3" => "ltss",

	"SUSE Linux Enterprise Module for HPC 12 SP2" => "generalsupport",
	"SUSE Enterprise Storage 1" => "eol",
	"SUSE OpenStack Cloud 6-LTSS" => "eol",
	"SUSE Linux Enterprise High Performance Computing 12 SP1" => "generalsupport",
	"SUSE Linux Enterprise Server 11-SECURITY" => "eol",
	"SUSE Cloud for SLE 12 Compute Nodes" => "eol",

	"SUSE Manager Proxy Module 4.0" => "eol",
	"SUSE Manager Server Module 4.0" => "eol",
	"SUSE Manager Proxy Module 4.1" => "eol",
	"SUSE Manager Server Module 4.1" => "eol",
	"SUSE Manager Retail Branch Server Module 4.1" => "eol",
	"SUSE Manager Proxy Module 4.2" => "eol",
	"SUSE Manager Server Module 4.2" => "eol",
	"SUSE Manager Retail Branch Server Module 4.2" => "eol",
	"SUSE Manager Proxy Module 4.3" => "generalsupport",
	"SUSE Manager Server Module 4.3" => "generalsupport",
	"SUSE Manager Retail Branch Server Module 4.3" => "generalsupport",
	"SUSE Linux Enterprise Micro for Rancher 5.3" => "generalsupport",
	"SUSE Linux Enterprise Micro for Rancher 5.4" => "generalsupport",
	"SUSE Linux Enterprise Micro for Rancher 5.5" => "generalsupport",
	"SUSE Enterprise Storage 1.0" => "eol",
	"SUSE Enterprise Storage 2" => "eol",

	"SUSE Linux Enterprise Installer Updates 15 SP1" => "ltss",
	"SUSE Linux Enterprise Installer Updates 15 SP2" => "ltss",
	"SUSE Linux Enterprise Installer Updates 15 SP3" => "ltss",
	"SUSE Linux Enterprise Installer Updates 15 SP4" => "ltss",
	"SUSE Linux Enterprise Installer Updates 15 SP5" => "generalsupport",
	"SUSE Linux Enterprise Installer Updates 15 SP6" => "generalsupport",

	"SUSE Manager Tools 12" => "generalsupport",
	"SUSE Manager Tools 15" => "generalsupport",
	"SUSE Manager Tools 15 SP1" => "generalsupport",
	"SUSE Manager Client Tools for SLE 15" => "generalsupport",
	"SUSE Manager Client Tools for SLE 12" => "generalsupport",
	"SUSE Manager Client Tools Beta for SLE 15" => "generalsupport",
	"SUSE Manager Client Tools Beta for SLE 12" => "generalsupport",
	"SUSE Manager Client Tools for RHEL, Liberty and Clones 8" => "generalsupport",
	"SUSE Manager Tools 12-BETA" => "generalsupport",
	"SUSE Manager Tools 15-BETA" => "generalsupport",
	"SUSE Manager Client Tools Beta for RHEL, Liberty and Clones 8" => "generalsupport",
	"SUSE Manager Client Tools for RHEL, Liberty and Clones 9-CLIENT-TOOLS" => "generalsupport",
	"SUSE Manager Client Tools Beta for SLE Micro 5" => "generalsupport",
	"SUSE Linux Enterprise Server 11 SP3-CLIENT-TOOLS" => "generalsupport",
	"SUSE Linux Enterprise Server 11 SP4-CLIENT-TOOLS" => "generalsupport",

	"SUSE Linux Enterprise Desktop 12 SP5" => "none",	# should not be there

	"SUSE Linux Enterprise Server for SAP All-in-One 11 SP4" => "eol",
	"SUSE Cloud Compute Node for SUSE Linux Enterprise 12 5" => "eol",

	"SUSE Manager Client Tools Beta for Ubuntu 1604" => "eol",
	"SUSE Manager Client Tools Beta for Ubuntu 1804" => "eol",
	"SUSE Manager Client Tools Beta for Ubuntu 2004" => "generalsupport",
	"SUSE Manager Client Tools Beta for Debian 10" => "generalsupport",
	"SUSE Manager Client Tools Beta for Debian 9" => "eol",

	"Subscription Management Tool 11 SP3" => "eol",
);

my $dn = `dirname $0`;chomp($dn);
my $cverepobase=`dirname $dn`;
chomp($cverepobase);

my $productmapurl	= "https://aimaas.suse.de/api/entity/products";
my $smeltproductsurl	= "https://smelt.suse.de/api/v1/basic/products/";

my $ua = LWP::UserAgent->new("keep_alive" => 1);
$ua->agent("cve-database/Products.pm");
$ua->timeout(300);      # we have very long queries... but lets keep it to 5 minutes

sub aimas_remap_name($) {
	my ($xname) = @_;

	if ($xname =~ /^SUSE/ || $xname =~ /^HPE/) {
		if ($xname !~ /[0-9]/) {
			# print STDERR "no version in $xname\n";
			return undef;
		}
		if ($xname =~ /(.*) ESPOS (.*)/) { return "$1 $2-ESPOS"; }
		if ($xname =~ /(.*) LTSS.EXTREME.CORE/) { return "$1 LTSS EXTREME CORE"; }
		if ($xname =~ /(.*) LTSS (.*)/) { return "$1 $2-LTSS"; }
		if ($xname =~ /(.*) BCL (.*)/) { return "$1 $2-BCL"; }

		return $xname;
	}
	if ($xname eq "") {
		warn "empty xname\n";
		return undef;
	}

	if ($xname =~ /^(.*) Module (.*)$/) {
		my $module = $1;
		my $version= $2;

		if (    ($version =~ /(\d*.SP\d)$/) ||
			($version =~ /(\d*)$/)
		) {
			my $ver = $1;

			$ver =~ s/-/ /; # 15-sp1 -> 15 sp1
			return "SUSE Linux Enterprise Module for $module $ver";
		}
	}
	# catch all
	return $xname;
}

sub aimas_get_url($) {
	my ($url) = @_;

	# print STDERR "getting $url\n";
	# Create a request
	my $req = HTTP::Request->new(GET => $url);
	$req->header( 'Accept' => 'application/json' );
	my $res = $ua->request($req);
	if ($res->is_success) {
		if ($res->content eq "") {
			print STDERR "empty result on retrieving $url?\n";
		}
		return $res->content;
	} else {
		print STDERR "ERROR on: $url:\n";
		print STDERR $res->status_line;
		print STDERR "\n";
		return "";
	}
}

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
my $today = sprintf("%d-%02d-%02d", $year+1900,$mon+1, $mday);

#print STDERR "today  is $today\n";
#my $res = "2022-10-03" cmp $today;
#print STDERR "compare 2022-10-03 and $today: $res\n";
#my $res = "2023-06-30" cmp $today;
#print STDERR "compare 2023-06-30 and $today: $res\n";

my $url = $productmapurl;
my $page = 1;
my $last = 1;
do {
	my $json = aimas_get_url($url);
	my $mapref;

        eval {
                $mapref = decode_json($json);
        } or do {
                die "json invalid: $json\n";
        };
	# print STDERR Dumper($mapref);

	my $items = $mapref->{"items"};
	$last = 1;
	foreach my $item (@{$items}) {
		# print STDERR Dumper($item);
		$last = 0;

		my $xname = $item->{'name'};
		my $name = aimas_remap_name($xname);
		next if (!defined($name));

		if (defined($Products::product2state{$name})) {
			warn "already have state for $name\n";
			next;
		}

		my $state = "generalsupport";

		# allow overrides.
		if (defined($item->{'end_of_gs'})) {
			if (defined($Products::product2endofgeneral{$name})) {
				warn "$name has end of general already?\n";
			}
			$Products::product2endofgeneral{$name} = $item->{'end_of_gs'};
		}
		if (defined($item->{'end_of_ltss'})) {
			if (defined($Products::product2endofltss{$name})) {
				warn "$name has end of ltss already?\n";
			}
			$Products::product2endofltss{$name} = $item->{'end_of_ltss'};
		}

		if (defined($Products::product2endofgeneral{$name})) {
			if (($Products::product2endofgeneral{$name} cmp $today) >= 0) {
				$state = "generalsupport";
			} else {
				$state = "eol";	# for cases where we have no ltss, if ltss will be overwritten
			}
		}
		if (defined($Products::product2endofltss{$name})) {
			if (!defined($Products::product2endofgeneral{$name})) { warn "$name has LTSS, but end of general?\n"; }
			if (	(($Products::product2endofgeneral{$name} cmp $today) < 0) &&
				(($Products::product2endofltss{$name}    cmp $today) >= 0)
			) {
				$state = "ltss";
			}
			if (($Products::product2endofltss{$name} cmp $today) < 0) {
				$state = "eol";
			}
		}

		if (defined($Products::product2state{$name})) {
			print STDERR "$name lifecycle state already defined ($Products::product2state{$name} vs $state), overwriting!\n";
		}

		$Products::product2state{$name} = $state;

		print STDERR "$name is $state\n" if -t STDERR;

#$VAR1 = {
#          'slug' => 'suse-sle-module-basesystem-15-sp3',
#          'end_of_ltss' => '2025-12-31',
#          'end_of_gs' => '2022-12-31',
#          'deleted' => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' ),
#          'name' => 'Basesystem Module 15 SP3',
#          'id' => 10
#        };

	}
	$page++;
	$url = "$productmapurl?page=$page";
} while (!$last);


# Also read SMELT products.

$url = $smeltproductsurl;
$page = 1;
$last = 1;
do {
	my $json = aimas_get_url($url);
	my $mapref;

        eval {
                $mapref = decode_json($json);
        } or do {
                die "json invalid: $json\n";
        };
	# print STDERR Dumper($mapref);

	my $items = $mapref->{"results"};
	$last = 1;
	foreach my $item (@{$items}) {
		$last = 0;

		my $friendlyname = $item->{'friendly_name'};
		my $name = $friendlyname;

		next if (!defined($name));

		my $details = $item->{'details'};
		foreach my $detail (@{$details}) {
			# print STDERR Dumper($detail);

			if ($detail->{'status'} eq "Undefined") {
				# print STDERR Dumper($item);
				print $detail->{'friendly_name'} . ": undefined\n" if -t STDERR;
			}
		}
	}
	$page++;
	$url = "$productmapurl?page=$page";
} while (!$last);

# overrides somer weird smash names
$Products::product2state{"SUSE Linux Enterprise Server Teradata 12 SP3"} = $Products::product2state{"SUSE Linux Enterprise Server 12 SP3 Teradata"};
$Products::product2state{"SUSE Linux Enterprise Server Teradata 15 SP4"} = $Products::product2state{"SUSE Linux Enterprise Server 15 SP4 Teradata"};
$Products::product2state{"Teradata 12-SP3 LTSS Extension"} = $Products::product2state{"SUSE Linux Enterprise Server Teradata LTSS 12 SP3"};
$Products::product2state{"SUSE Linux Enterprise Server 12 SP5 LTSS Extended Security"} = $Products::product2state{"SUSE Linux Enterprise Server LTSS Extended Security 12 SP5"};
$Products::product2state{"Carwos 1"} = $Products::product2state{"SUSE Carwos 1"};

1;
