Commit 019a2184 authored by Leigh B Stoller's avatar Leigh B Stoller
Browse files

Main part of tracking what images a profile uses.

parent af5c4bf9
......@@ -51,6 +51,7 @@ use APT_Dataset;
use GeniXML;
use GeniHRN;
use libtestbed;
use Project;
use Lease;
use English;
use Data::Dumper;
......@@ -64,6 +65,7 @@ my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $OURDOMAIN = "@OURDOMAIN@";
my $MYURN = "urn:publicid:IDN+${OURDOMAIN}+authority+cm";
my $MAINSITE = @TBMAINSITE@;
# Concat id/vers.
sub versid($)
......@@ -113,6 +115,19 @@ sub BlessRow($$)
or return undef;
}
$self->{'WEBTASK'} = $webtask;
#
# If not deleted, then grab the image info records.
#
if (!defined($self->deleted())) {
my $images;
return undef
if (APT_Profile::ImageInfo->LookupForProfile($self, \$images));
$self->{'IMAGES'} = $images;
}
else {
$self->{'IMAGES'} = {};
}
return $self;
}
......@@ -130,7 +145,9 @@ sub Lookup($$;$$)
if (!defined($arg2)) {
if ($arg1 =~ /^(\d*)$/) {
my $result =
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid ".
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid, ".
" i.disabled as profile_disabled, ".
" i.nodelete as profile_nodelete ".
" from apt_profiles as i ".
"left join apt_profile_versions as v on ".
" v.profileid=i.profileid and ".
......@@ -144,7 +161,9 @@ sub Lookup($$;$$)
elsif ($arg1 =~ /^([-\w]*),([-\w\.\+]*)$/ ||
$arg1 =~ /^([-\w]*)\/([-\w\.\+]*)$/) {
my $result =
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid ".
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid, ".
" i.disabled as profile_disabled, ".
" i.nodelete as profile_nodelete ".
" from apt_profiles as i ".
"left join apt_profile_versions as v on ".
" v.profileid=i.profileid and ".
......@@ -158,7 +177,9 @@ sub Lookup($$;$$)
elsif ($arg1 =~ /^([-\w]*),([-\w\.\+]*):(\d*)$/ ||
$arg1 =~ /^([-\w]*)\/([-\w\.\+]*):(\d*)$/) {
my $result =
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid ".
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid, ".
" i.disabled as profile_disabled, ".
" i.nodelete as profile_nodelete ".
" from apt_profiles as i ".
"left join apt_profile_versions as v on ".
" v.profileid=i.profileid ".
......@@ -176,7 +197,9 @@ sub Lookup($$;$$)
# version with the uuid.
#
my $result =
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid ".
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid, ".
" i.disabled as profile_disabled, ".
" i.nodelete as profile_nodelete ".
" from apt_profiles as i ".
"left join apt_profile_versions as v on ".
" v.profileid=i.profileid and ".
......@@ -188,7 +211,9 @@ sub Lookup($$;$$)
if ($result->numrows);
$result =
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid ".
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid, ".
" i.disabled as profile_disabled, ".
" i.nodelete as profile_nodelete ".
" from apt_profile_versions as v ".
"left join apt_profiles as i on ".
" v.profileid=i.profileid ".
......@@ -203,7 +228,9 @@ sub Lookup($$;$$)
elsif (!defined($arg3)) {
if ($arg1 =~ /^\d+$/ && $arg2 =~ /^\d+$/) {
my $result =
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid ".
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid, ".
" i.disabled as profile_disabled, ".
" i.nodelete as profile_nodelete ".
" from apt_profiles as i ".
"left join apt_profile_versions as v on ".
" v.profileid=i.profileid ".
......@@ -216,7 +243,9 @@ sub Lookup($$;$$)
}
elsif ($arg1 =~ /^[-\w]*$/ && $arg2 =~ /^([-\w\.\+]*):(\d+)$/) {
my $result =
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid ".
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid, ".
" i.disabled as profile_disabled, ".
" i.nodelete as profile_nodelete ".
" from apt_profiles as i ".
"left join apt_profile_versions as v on ".
" v.profileid=i.profileid ".
......@@ -229,7 +258,9 @@ sub Lookup($$;$$)
}
elsif ($arg1 =~ /^[-\w]*$/ && $arg2 =~ /^[-\w\.\+]*$/) {
my $result =
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid ".
DBQueryWarn("select i.*,v.*,i.uuid as profile_uuid, ".
" i.disabled as profile_disabled, ".
" i.nodelete as profile_nodelete ".
" from apt_profiles as i ".
"left join apt_profile_versions as v on ".
" v.profileid=i.profileid and ".
......@@ -274,6 +305,17 @@ AUTOLOAD {
carp("No such slot '$name' field in class $type");
return undef;
}
sub images($;$)
{
my ($self, $client_id) = @_;
if (!defined($client_id)) {
return $self->{'IMAGES'};
}
elsif (exists($self->{'IMAGES'}->{$client_id})) {
return $self->{'IMAGES'}->{$client_id};
}
return undef;
}
# Break circular reference someplace to avoid exit errors.
sub DESTROY {
......@@ -281,6 +323,7 @@ sub DESTROY {
$self->{'WEBTASK'} = undef;
$self->{'DBROW'} = undef;
$self->{'IMAGES'} = undef;
}
sub IsRepoBased($) {
......@@ -290,6 +333,21 @@ sub IsRepoBased($) {
}
sub webtask($) { return $_[0]->{'WEBTASK'}; }
# A profile is disabled if version is disabled or entire profile is disabled
sub isDisabled($)
{
my ($self) = @_;
return ($self->disabled() || $self->profile_disabled() ? 1 : 0);
}
# Ditto nodelete.
sub isLocked($)
{
my ($self) = @_;
return ($self->nodelete() || $self->profile_nodelete() ? 1 : 0);
}
#
# Refresh a class instance by reloading from the DB.
#
......@@ -611,6 +669,9 @@ sub Delete($$)
DBQueryWarn("delete from apt_profile_favorites ".
"where profileid='$profileid'")
or goto bad;
DBQueryWarn("delete from apt_profile_images ".
"where profileid='$profileid'")
or goto bad;
DBQueryWarn("delete from apt_profiles where profileid='$profileid'")
or goto bad;
......@@ -666,10 +727,69 @@ sub DeleteVersion($)
if (!DBQueryWarn("update apt_profiles set version=$newhead ".
"where profileid='$profileid' and ".
" version='$version'"));
goto bad
if (!DBQueryWarn("delete from apt_profile_images ".
"where profileid='$profileid' and ".
" version='$version'"));
DBQueryWarn("unlock tables");
return 0;
bad:
DBQueryWarn("unlock tables");
return -1;
}
#
# Recover a deleted version of a profile.
# The profile itself cannot be fully deleted for this to work.
#
sub UnDeleteVersion($$)
{
my ($self, $version);
my $profileid = $self->profileid();
DBQueryWarn("lock tables apt_profile_versions write, ".
" apt_profiles write, web_tasks write")
or return -1;
#
# Confirm if this is going to become the new head version.
#
my $query_result =
DBQueryWarn("select version from apt_profiles ".
"where profileid='$profileid'");
goto bad
if (!$query_result || !$query_result->numrows);
my ($curhead) = $query_result->fetchrow_array();
#
# We need a new web task.
#
my $webtask = WebTask->CreateAnonymous();
if (!defined($webtask)) {
print STDERR "Could not create a new webtask\n";
goto bad;
}
my $webtask_id = $webtask->task_id();
goto bad
if (!DBQueryWarn("update apt_profile_versions set ".
" webtask_id='$webtask_id', deleted=null ".
"where profileid='$profileid' and ".
" version='$version'"));
# Is this the new head version?
if ($version > $curhead) {
goto bad
if (!DBQueryWarn("update apt_profiles set version='$version' ".
"where profileid='$profileid'"));
}
DBQueryWarn("unlock tables");
return 0;
bad:
DBQueryWarn("unlock tables");
$webtask->Delete()
if (defined($webtask));
return -1;
}
......@@ -1350,6 +1470,172 @@ sub IsHead($)
return ($head == $self->version() ? 1 : 0);
}
sub HeadVersionNumber($)
{
my ($self) = @_;
my $profileid = $self->profileid();
my $query_result =
DBQueryWarn("select max(version) from apt_profile_versions ".
"where profileid='$profileid' and deleted is null");
return -1
if (!$query_result || !$query_result->numrows);
my ($head) = $query_result->fetchrow_array();
return $head;
}
# Number of undeleted versions.
sub VersionCount($)
{
my ($self) = @_;
my $profileid = $self->profileid();
my $query_result =
DBQueryWarn("select count(*) from apt_profile_versions ".
"where profileid='$profileid' and deleted is null");
return -1
if (!$query_result || !$query_result->numrows);
my ($count) = $query_result->fetchrow_array();
return $count;
}
# Insert an image record.
sub InsertImageRecord($$$)
{
my ($self, $client_id, $image) = @_;
my $name = $self->name();
my $profileid = $self->profileid();
my $version = $self->version();
my $pid = $self->pid();
my $pid_idx = $self->pid_idx();
my $gid = $self->gid();
my $gid_idx = $self->gid_idx();
my $safe_id = DBQuoteSpecial($client_id);
my $safe_image= DBQuoteSpecial($image);
my $safe_auth = "null";
my $safe_ospid= "null";
my $safe_os = "null";
my $safe_vers = "null";
my $safe_lpid = "null";
if (GeniHRN::IsValid($image)) {
my $hrn = GeniHRN->new($image);
my ($authority, $ospid, $os, $vers) = $hrn->ParseImage();
if (defined($authority) && $authority ne "") {
$safe_auth = DBQuoteSpecial($authority)
}
if (defined($ospid) && $ospid ne "") {
$safe_ospid = DBQuoteSpecial($ospid);
}
if (defined($os) && $os ne "") {
$safe_os = DBQuoteSpecial($os);
}
if (defined($vers) && $vers =~ /^\d+$/) {
$safe_vers = DBQuoteSpecial($vers);
}
# Strip version;
$image =~ s/:\d+$//;
# This // vs : thing is a pain.
$image =~ s/\/\//:/;
my $safe_foo = DBQuoteSpecial($image);
# Try to map local project.
my $lpid;
if ($hrn->domain() eq $OURDOMAIN && defined($ospid)) {
my $project = Project->Lookup($ospid);
if (defined($project)) {
$lpid = $project->pid();
}
}
if (!defined($lpid) && $MAINSITE) {
#
# Use the image server to map the image to a local project urn.
#
my $query_result =
DBQueryWarn("select project_urn from ims.images ".
"where urn=$safe_foo");
if ($query_result && $query_result->numrows) {
my ($project_urn) = $query_result->fetchrow_array();
my $phrn = GeniHRN->new($project_urn);
$lpid = $phrn->project();
}
}
$safe_lpid = DBQuoteSpecial($lpid)
if (defined($lpid));
}
return -1
if (!DBQueryWarn("replace into apt_profile_images set ".
" name='$name', profileid=$profileid, ".
" version='$version', ".
" pid='$pid',pid_idx='$pid_idx', ".
" gid='$gid',gid_idx='$gid_idx', ".
" client_id=$safe_id, ".
" authority=$safe_auth,ospid=$safe_ospid, ".
" os=$safe_os,osvers=$safe_vers,".
" local_pid=$safe_lpid, ".
" image=$safe_image"));
return 0;
}
#
# Look at the rspec and find all images being used.
#
sub InsertImageRecords($$)
{
my ($self, $perrmsg) = @_;
my $profileid = $self->profileid();
my $version = $self->version();
my $rspec = GeniXML::Parse($self->rspec());
if (! defined($rspec)) {
$$perrmsg = "Could not parse rspec\n";
return -1;
}
#
# First make sure we can find all the images.
#
my %images = ();
foreach my $ref (GeniXML::FindNodes("n:node", $rspec)->get_nodelist()) {
my $client_id = GetVirtualId($ref);
my $diskref = GeniXML::GetDiskImage($ref);
my $image_urn;
if (defined($diskref)) {
$image_urn = GeniXML::GetText("name", $diskref);
}
if (defined($image_urn)) {
next if
(!GeniHRN::IsValid($image_urn));
my $hrn = GeniHRN->new($image_urn);
my ($authority, $ospid, $os, $vers) = $hrn->ParseImage();
if (!defined($ospid)) {
print STDERR "$image_urn\n";
next;
}
$images{$client_id} = $image_urn;
}
}
# Now delete the existing records.
DBQueryWarn("delete from apt_profile_images ".
"where profileid='$profileid' and version='$version'")
or return -1;
# And new ones.
foreach my $client_id (keys(%images)) {
$self->InsertImageRecord($client_id, $images{$client_id}) == 0
or return -1;
}
return 0;
}
#
# Publish a profile. Not sure what this really means yet.
#
......@@ -1390,5 +1676,138 @@ sub AdminURL($)
return $wwwbase . "/manage_profile.php?uuid=$uuid";
}
#
# Return a list of all profile versions.
#
sub AllVersions($)
{
my ($self) = @_;
my $profileid = $self->profileid();
my @result = ();
my $query_result =
DBQueryWarn("select profileid,version from apt_profile_versions ".
"where profileid='$profileid' and deleted is null ".
"order by version desc");
return ()
if (!$query_result || !$query_result->numrows);
while (my ($profileid,$version) = $query_result->fetchrow_array()) {
my $profile = APT_Profile->Lookup($profileid, $version);
push(@result, $profile)
if ($profile);
}
return @result;
}
###################################################################
package APT_Profile::ImageInfo;
use emdb;
use Carp;
use English;
use GeniHRN;
use Data::Dumper;
use overload ('""' => 'Stringify');
use vars qw($AUTOLOAD);
#
# Stringify for output.
#
sub Stringify($)
{
my ($self) = @_;
my $pid = $self->pid();
my $os = $self->os();
my $client_id = $self->client_id();
my $name = $self->name();
my $version = $self->version();
my $osvers = "";
if ($self->osvers()) {
$osvers = ":" . $self->osvers();
}
return "[ImageInfo: $pid,$name,$version,$client_id,${os}${osvers}]";
}
#
# Lookup all image records for a profile. This is for a specfic
# version of a profile.
#
sub LookupForProfile($$$)
{
my ($class, $profile, $pref) = @_;
my $profileid = $profile->profileid();
my $version = $profile->version();
my %result = ();
my $query_result =
DBQueryWarn("select * from apt_profile_images ".
"where profileid='$profileid' and version='$version'");
return -1
if (!defined($query_result));
while (my $row = $query_result->fetchrow_hashref()) {
my $client_id = $row->{'client_id'};
my $self = {};
$self->{'DBROW'} = $row;
bless($self, $class);
$result{$client_id} = $self;
}
$$pref = \%result;
return 0;
}
#
# Find profiles using this image, that are not the profile associated
# with this image.
#
sub FindProfilesUsing($$)
{
my ($self, $pref) = @_;
my $safe_urn;
my @result = ();
if (ref($self)) {
$safe_urn = DBQuoteSpecial($self->image());
}
elsif (GeniHRN::IsValid($self)) {
$safe_urn = DBQuoteSpecial($self);
}
else {
return -1;
}
my $query_result =
DBQueryWarn("select distinct profileid,version ".
" from apt_profile_images ".
"where image=$safe_urn ".
"order by name,version");
return -1
if (!$query_result);
while (my ($id,$vers) = $query_result->fetchrow_array()) {
my $profile = APT_Profile->Lookup($id, $vers);
next
if (!defined($profile));
push(@result, $profile);
}
@$pref = @result;
return 0;
}
AUTOLOAD {
my $self = $_[0];
my $type = ref($self) or croak "$self is not an object";
my $name = $AUTOLOAD;
$name =~ s/.*://; # strip fully-qualified portion
# A DB row proxy method call.
if (exists($self->{'DBROW'}->{$name})) {
return $self->{'DBROW'}->{$name};
}
carp("No such slot '$name' field in class $type");
return undef;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment