
| Current Path : /var/www/web-klick.de/dsh/10_customer2017/1204__intel/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : /var/www/web-klick.de/dsh/10_customer2017/1204__intel/CmDbClient.pm |
package CmDbClient;
use strict;
use warnings;
use Params::Validate qw(:all);
use LWP::UserAgent;
use YAML::XS qw(Dump Load);
our $VERSION = "0.30";
# usage:
#
# my $cdc = CmDbClient->new(HOST => $host, PORT => $port);
#
sub new {
my $class = shift;
my $this = {};
bless $this, $class;
$this->initialize(@_);
return $this;
}
sub initialize {
my $this = shift;
my %args = validate(@_, {
HOST => { type => SCALAR },
PORT => { type => SCALAR|UNDEF, optional => 1 },
VERBOSITY => { type => SCALAR, default => 0 },
LOG_INFO => { type => CODEREF, default => sub { print @_ } },
LOG_WARN => { type => CODEREF, default => sub { warn @_ } }
});
@$this{keys %args} = values %args;
$this->{LOG_INFO} ||= sub { print @_ };
$this->{LOG_WARN} ||= sub { warn @_ };
# Create a user agent object
$this->{_UA} = LWP::UserAgent->new;
$this->{_UA}->default_header(Accept => 'text/x-yaml');
$this->{_UA}->agent("CmDbClient/$VERSION");
return $this;
}
sub log_info
{
my ($this, $verbose, @args) = @_;
$this->{LOG_INFO}->(@args) if $verbose <= $this->{VERBOSITY};
}
sub log_warn
{
my ($this, $verbose, @args) = @_;
$this->{LOG_WARN}->(@args) if $verbose <= $this->{VERBOSITY};
}
sub config
{
my $this = shift;
my %args = @_;
foreach(keys %args) {
my $val = $args{$_};
if(defined $val) {
$this->{$_} = $val;
} else {
delete $this->{$_};
}
}
1;
}
sub parse_acs_definition
{
my ($this, $acsdef) = @_;
my ($user,$project,$acs,$rev);
if($acsdef && $acsdef =~ m{^(?:(\w*)\@|)(?:(\w*):|)([^\@:#]+)(?:#(\w*)|)$}) {
return($1,$2,$3,$4);
}
elsif($acsdef) {
$this->log_warn(0, "[ERROR] Cannot parse ACS definition '$acsdef' - it does not conform to the syntax ([user@]project:acs#revision).\n");
}
return;
}
sub write_acs_definition
{
my $this = shift;
my %args = validate(@_, {
USER => { type => SCALAR|UNDEF, optional => 1 },
PROJECT => { type => SCALAR|UNDEF, optional => 1 },
ACS => { type => SCALAR },
REVISION => { type => SCALAR|UNDEF, optional => 1 },
});
my $acs = defined($args{USER}) ? "$args{USER}\@" : '';
$acs .= $args{PROJECT} ? "$args{PROJECT}:" : '';
$acs .= $args{ACS} ? $args{ACS} : '';
$acs .= $args{REVISION} ? "#$args{REVISION}" : '';
return $acs;
}
sub _request {
my $this = shift;
my %args = validate(@_, {
'PATH' => { type => SCALAR }
});
# TODO timeout?
my $host = $this->{HOST};
if($this->{PORT}) {
$host .= ':'.$this->{PORT};
}
my $res = $this->{_UA}->get("$host/rest-api/$args{PATH}");
# Check the outcome of the response
unless($res->is_success) {
$this->log_warn(0, "[ERROR] Server error: ".$res->status_line."\n");
return;
}
return $res;
}
# usage:
#
# my @projects = $cdc->get_projects(USER => $user);
# ...
sub get_projects {
my $this = shift;
my %args = validate(@_, {
'USER' => { type => SCALAR, optional => 1 }
});
my $res = $args{USER} ?
$this->_request(PATH => "user/$args{USER}/project") :
$this->_request(PATH => 'project');
return unless $res;
my $data = Load($res->content);
if(wantarray && ref($data) eq 'ARRAY') {
return @$data;
}
return $data;
}
# types of ACSes: ACS (with inheritance resolved), ACS_raw (just the ACS, no processing)
sub get_ACS_types {
my $this = shift;
my %args = validate(@_, {
'USER' => { type => SCALAR, optional => 1 },
'PROJECT' => { type => SCALAR }
});
my $res = $args{USER} ?
$this->_request(PATH => "user/$args{USER}/project/$args{PROJECT}") :
$this->_request(PATH => "project/$args{PROJECT}");
return unless $res;
my $data = Load($res->content);
if(wantarray && ref($data) eq 'ARRAY') {
return @$data;
}
return $data;
}
# if USER is provided: only well known and user private ACSes
# all ACSes otherwise
sub get_ACS_list {
my $this = shift;
my %args = validate(@_, {
'USER' => { type => SCALAR, optional => 1 },
'PROJECT' => { type => SCALAR },
'TYPE' => { type => SCALAR, default => 'ACS' }
});
my $res = $args{USER} ?
$this->_request(PATH => "user/$args{USER}/project/$args{PROJECT}/$args{TYPE}") :
$this->_request(PATH => "project/$args{PROJECT}/$args{TYPE}");
return unless $res;
my $data = Load($res->content);
if(wantarray && ref($data) eq 'ARRAY') {
return @$data;
}
return $data;
}
sub get_ACS_rev_list {
my $this = shift;
my %args = validate(@_, {
'USER' => { type => SCALAR, optional => 1 },
'PROJECT' => { type => SCALAR },
'TYPE' => { type => SCALAR, default => 'ACS' },
'ACS' => { type => SCALAR }
});
my $res = $args{USER} ?
$this->_request(PATH => "user/$args{USER}/project/$args{PROJECT}/$args{TYPE}/$args{ACS}") :
$this->_request(PATH => "project/$args{PROJECT}/$args{TYPE}/$args{ACS}");
return unless $res;
my $data = Load($res->content);
if(wantarray && ref($data) eq 'ARRAY') {
return @$data;
}
}
# returns a hash of
#
# VOBS: list of (VOB_name, ibranch, rev)
#
# VOB roots violate the disjointness property of component definitions
# but there are unfortunatly some files directly in them.
#
# the list does not necessarily contain all VOBs of a project (ususally
# just project VOBs as there are files directly in these roots)
#
# the generated config spec entry should just cover the files in the
# VOB root (non-recursivly)
#
# CnD: ibranch, rev
#
# rev = n | 'HEAD'
#
# to be looked up with get_CnD()
#
# CONFIG: CxD configuration
# returns a hash:
# 'cnd' => 's4g_main.HEAD',
# # domain # selector
# 'component' => { 'tx' => { 'design' => 's4g_main.5',
# 'concept' => 's4g_main.HEAD' },
# 'rx' => { 'design' => 's4g_main.3',
# 'concept' => 's4g_main.HEAD' } },
# 'vobs' => { '//slc-S4G-prj' => 's4g_main.HEAD' },
# 'on-integration' => '/path/to/smoke-test-script'
sub get_ACS {
my $this = shift;
my %args = validate(@_, {
'USER' => { type => SCALAR, optional => 1 },
'PROJECT' => { type => SCALAR },
'TYPE' => { type => SCALAR, default => 'ACS' },
'ACS' => { type => SCALAR },
'REV' => { type => SCALAR }
});
my $res = $args{USER} ?
$this->_request(PATH => "user/$args{USER}/project/$args{PROJECT}/$args{ACS}/$args{REV}") :
$this->_request(PATH => "project/$args{PROJECT}/$args{TYPE}/$args{ACS}/$args{REV}");
return unless $res;
my $data = Load($res->content);
if(wantarray && ref($data) eq 'HASH') {
return %$data;
}
$data->{_this} = $this;
return bless($data, 'ACS');
}
# TODO:
# get_CnD_branches
# get_CnD_branch_revs
# usage: $cdc->get_CnD(PROJECT => 'S4G', REV => [ 'slc_main', 'HEAD' ])
# returns a hash:
# 'domain' => { 'concept' => [ '//*/units/*/source/sc',
# '//*/units/*/source/ccss' ] },
# 'component' => { 'tx' => [ '//smartilu-LUP-fe_dig/units/tx_fsm',
# '//sc_tx' ],
# 'rx' => [ '//sartilu-LUP-fe_dig/units/rx_fsm',
# '//smartilu-LUP-fe_dig/units/rx_dsp' ] },
# 'raw' => 's4g_main.5'
sub get_CnD {
my $this = shift;
my %args = validate(@_, {
'PROJECT' => { type => SCALAR },
'REV' => { type => ARRAYREF }
});
my ($branch, $rev) = @{$args{REV}};
my $res = $this->_request(PATH => "project/$args{PROJECT}/CnD/$branch/$rev");
return unless $res;
my $data = Load($res->content);
if(wantarray && ref($data) eq 'HASH') {
return %$data;
}
$data->{_this} = $this;
return bless($data, 'CnD');
}
##############################################################################
package ACS;
use YAML::XS qw(Dump);
sub new
{
return bless(+{}, __PACKAGE__);
}
# returns hash of compoent.domain and selector:
# component => {
# domain => 'selector'
# ...
# },
# ...
sub getComponents
{
my $this = shift;
if($this->{component}) {
return %{$this->{component}};
}
return ();
}
# return hash of VOBs and selectors:
# vob => 'selector'
# ...
sub getVobs
{
my $this = shift;
if($this->{vobs}) {
return %{$this->{vobs}};
}
return ();
}
sub getCnDSelector
{
my $this = shift;
return $this->{cnd};
}
sub getIntegrationCommand
{
my $this = shift;
return $this->{'on-integration'};
}
sub getIncludeFileSelector
{
my $this = shift;
my $val = $this->{'custom-config-include-file'};
unless($val) {
return;
}
elsif(ref($val) eq 'ARRAY') {
return @$val;
}
elsif($val =~ /(\S+)\s+(\S+)/) {
return ($1,$2);
}
else {
$this->{_this}->log_warn(0, "[ERROR] No correct custom config include file definition:\n".
Dump($val));
return;
}
#$val =~ s/^\s+|\s+$//g;
#return split(/\s+/, $val); # two items
}
sub getIntegrationBranch
{
my $this = shift;
my $cnd = $this->getCnDSelector();
if($cnd =~ /^([^.]+)\./) {
return $1;
}
return;
}
sub getCustomLoadRules
{
my $this = shift;
my $val = $this->{'custom-load-rules'};
unless($val) {
return;
}
elsif(ref($val) eq 'ARRAY') {
return @$val;
}
else {
$this->{_this}->log_warn(0, "[ERROR] No correct custom load rule definition:\n".
Dump($val));
return;
}
}
##############################################################################
package CnD;
sub new
{
return bless(+{}, __PACKAGE__);
}
sub getComponents
{
my $this = shift;
if($this->{component}) {
return %{$this->{component}};
}
return ();
}
sub getDomains
{
my $this = shift;
if($this->{domain}) {
return %{$this->{domain}};
}
return ();
}
sub getRawRevision
{
my $this = shift;
return $this->{domain}->{raw};
}
1;
__END__
schema example
------------------------------------------------------------------------------
ACS
cnd: <integ-branch-name>.<revision>
Note:
corresponding to file: <integ-branch-name>.<revision>.cnd
<revision> may be HEAD
component:
<component>:
<domain>: <branch>.<selector>
...
inherit: <acs-name>/<revision>
vobs:
//<tag>: <branch>.<selector>
...
on-integration: //<vob-tag>/<path>/<script>
custom-config-include-file:
//<vob-tag>/<path>/<file>
<branch>.<selector>
custom-load-rules:
//slc-S4G-prj/lib/p/common
//slc-S4G-prj/lib/matlab
------------------------------------------------------------------------------
CnD