Skip to content

Commit

Permalink
ui: add /app/project/:id with propagation
Browse files Browse the repository at this point in the history
  • Loading branch information
andrii-suse committed Feb 29, 2024
1 parent 57fc805 commit b6d6079
Show file tree
Hide file tree
Showing 19 changed files with 249 additions and 15 deletions.
1 change: 1 addition & 0 deletions assets/assetpack.def
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
< javascripts/admin_user.js
< javascripts/audit_log.js
< javascripts/server.js
< javascripts/project.js
< https://raw.githubusercontent.com/bootstrapthemesco/bootstrap-4-multi-dropdown-navbar/beta2.0/js/bootstrap-4-navbar.js
< https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.js
< https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.js
Expand Down
16 changes: 15 additions & 1 deletion assets/javascripts/admintable.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,17 @@ function renderAdminTableHostname(data, type, row, meta) {
return data? '<a href="/app/server/'+ htmlEscape(data) +'">' + htmlEscape(data) + '</>' : '';
}

function renderAdminTableProjectName(data, type, row, meta) {
if (type !== 'display') {
return data ? data : '';
}
if (isEditingAdminTableRow(meta)) {
return '<input type="text" value="' + htmlEscape(data) + '"/>';
}
return data? '<a href="/app/project/'+ row['id'] +'">' + htmlEscape(data) + '</>' : '';
}


function renderAdminTableLongText(data, type, row, meta) {
if (type !== 'display') {
return data ? data : '';
Expand Down Expand Up @@ -382,6 +393,8 @@ function setupAdminTable(editable) {
var emptyRow = {};
var columns = [];
var columnDefs = [];
var url = $("#admintable_api_url").val() + window.location.search;

var thElements = $('.admintable thead th').each(function() {
var th = $(this);

Expand All @@ -403,6 +416,8 @@ function setupAdminTable(editable) {
if (th.hasClass('col_value')) {
if (columnName == 'hostname') {
columnDef.render = renderAdminTableHostname;
} else if (columnName == 'name' && url && url.startsWith('/rest/project')) {
columnDef.render = renderAdminTableProjectName;
} else if (columnName == 'public notes' || columnName == 'comment' || columnName == 'sponsor') {
columnDef.render = renderAdminTableLongText;
} else {
Expand All @@ -429,7 +444,6 @@ function setupAdminTable(editable) {
});

// setup admin table
var url = $("#admintable_api_url").val() + window.location.search;
var table = $('.admintable');
var dataTable = table.DataTable({
order: [
Expand Down
11 changes: 11 additions & 0 deletions assets/javascripts/project.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function setupProjectPropagation(id) {
var table = $('#project_propagation');
var dataTable = table.DataTable({
ajax: {
url: '/rest/project/propagation/' + id,
},
deferRender: true,
columns: [{data: 'dt'}, {data: 'prefix'}, {data: 'version'}, {data: 'mirrors'}],
order: [[0, 'desc']],
});
}
2 changes: 2 additions & 0 deletions lib/MirrorCache/Schema/Result/Project.pm
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ __PACKAGE__->add_columns(
db_sync_full_every => { data_type => "integer", is_nullable => 1 },
);


__PACKAGE__->set_primary_key("id");
1;
7 changes: 7 additions & 0 deletions lib/MirrorCache/Schema/ResultSet/Rollout.pm
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ sub add_rollout_server {
my $dbh = $self->result_source->schema->storage->dbh;

my $sql = 'insert into rollout_server(rollout_id, server_id, dt) select ?, ?, now()';

if ($dbh->{Driver}->{Name} eq 'Pg') {
$sql = $sql . ' on conflict do nothing';
} else {
$sql = $sql . ' on duplicate key update server_id = server_id';
}

$dbh->prepare($sql)->execute($rollout_id, $server_id);
return 1;
}
Expand Down
12 changes: 10 additions & 2 deletions lib/MirrorCache/WebAPI.pm
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,12 @@ sub _setup_webui {
$rest_r->get('/server/location') ->to('server_location#list');
$rest_r->get('/server/:id')->to('table#list', table => 'Server');
$rest_r->get('/server/check/:id')->name('rest_get_server_check')->to('server_note#list_incident');
$rest_r->get('/project')->to('project#list');
$rest_r->get('/project/:name')->to('project#show');
$rest_r->get('/project')->name('rest_project')->to('table#list', table => 'Project');
# $rest_r->get('/project/:name')->to('project#show');
$rest_r->get('/project/:id')->to('table#list', table => 'Project');
$rest_r->get('/project/:name/mirror_summary')->to('project#mirror_summary');
$rest_r->get('/project/:name/mirror_list')->to('project#mirror_list');
$rest_r->get('/project/propagation/:project_id')->to('project_propagation#list');

my $rest_operator_auth;
$rest_operator_auth = $rest->under('/')->to('session#ensure_operator');
Expand All @@ -196,6 +198,10 @@ sub _setup_webui {
$rest_operator_r->get('/server/contact/#hostname')->name('rest_get_server_contact')->to('server_note#list_contact');
$rest_operator_r->post('/sync_tree')->name('rest_post_sync_tree')->to('folder_jobs#sync_tree');

$rest_operator_r->post('/project')->to('table#create', table => 'Project');
$rest_operator_r->post('/project/:id')->name('post_project')->to('table#update', table => 'Project');
$rest_operator_r->delete('/project/:id')->to('table#destroy', table => 'Project');

$rest_r->get('/myserver')->name('rest_myserver')->to('table#list', table => 'MyServer');
$rest_r->get('/myserver/:id')->to('table#list', table => 'MyServer');
my $rest_usr_auth;
Expand Down Expand Up @@ -229,6 +235,8 @@ sub _setup_webui {
$app_r->get('/myserver')->name('myserver')->to('myserver#index');
$app_r->get('/folder')->name('folder')->to('folder#index');
$app_r->get('/folder/<id:num>')->name('folder_show')->to('folder#show');
$app_r->get('/project')->name('project')->to('project#index');
$app_r->get('/project/#id')->name('project_show')->to('project#show');

my $admin = $r->any('/admin');
my $admin_auth = $admin->under('/')->to('session#ensure_admin')->name('ensure_admin');
Expand Down
2 changes: 1 addition & 1 deletion lib/MirrorCache/WebAPI/Controller/App/Folder.pm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2014 SUSE LLC
# Copyright (C) 2024 SUSE LLC
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
Expand Down
41 changes: 41 additions & 0 deletions lib/MirrorCache/WebAPI/Controller/App/Project.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright (C) 2024 SUSE LLC
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, see <http://www.gnu.org/licenses/>.

package MirrorCache::WebAPI::Controller::App::Project;
use Mojo::Base 'MirrorCache::WebAPI::Controller::App::Table';

sub index {
my $c = shift;

$c->SUPER::admintable('project');
}

sub show {
my $self = shift;
my $id = $self->param('id');

my $f = $self->schema->resultset('Project')->find($id)
or return $self->reply->not_found;

my $info = {
id => $f->id,
path => $f->path,
name => $f->name,
};

return $self->render('app/project/show', project => $info);
}

1;
4 changes: 2 additions & 2 deletions lib/MirrorCache/WebAPI/Controller/Rest/Project.pm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2022 SUSE LLC
# Copyright (C) 2022,2024 SUSE LLC
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
Expand All @@ -15,11 +15,11 @@

package MirrorCache::WebAPI::Controller::Rest::Project;
use Mojo::Base 'Mojolicious::Controller';
use Mojo::Promise;

sub show {
my ($self) = @_;
my $name = $self->param("name");
return $self->render(code => 400, text => "Mandatory argument is missing") unless $name;

my $prj = $self->schema->resultset('Project')->find({ name => $name });

Expand Down
48 changes: 48 additions & 0 deletions lib/MirrorCache/WebAPI/Controller/Rest/ProjectPropagation.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright (C) 2024 SUSE LLC
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, see <http://www.gnu.org/licenses/>.

package MirrorCache::WebAPI::Controller::Rest::ProjectPropagation;
use Mojo::Base 'Mojolicious::Controller';
use Data::Dumper;

sub list {
my ($self) = @_;

my $project_id = $self->param("project_id");

return $self->render(code => 400, text => "Mandatory argument is missing") unless $project_id;

my $sql = <<'END_SQL';
with propagation as (
select prefix, rollout_server.dt, epc, version, count(*) as mirror_count
from
rollout_server
join rollout on id = rollout_id
where rollout.project_id = ?
group by prefix, version, epc, rollout_server.dt
)
select p2.prefix, p2.dt, p2.version, sum(p1.mirror_count) as mirrors
from propagation p1
join propagation p2 on p1.epc = p2.epc and p1.dt <= p2.dt and p1.prefix = p2.prefix
group by p2.prefix, p2.dt, p2.version
order by p2.dt desc
END_SQL

my $res = $self->schema->storage->dbh->selectall_arrayref($sql, {Columns => {}}, $project_id);

return $self->render(json => { data => $res });
}

1;
9 changes: 8 additions & 1 deletion lib/MirrorCache/WebAPI/Controller/Rest/Table.pm
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ my %tables = (
keys => [['id'], ['path'],],
cols => ['id', 'path', 'wanted', 'sync requested', 'sync scheduled', 'sync last', 'scan requested', 'scan scheduled', 'scan last'],
},
Project => {
keys => [['id'], ['name'],],
cols => ['id', 'name', 'path'],
},
);

sub _myserver {
Expand Down Expand Up @@ -144,7 +148,10 @@ sub create {

my $table = $self->param("table");

my %entry = %{$tables{$table}->{defaults}};
my %entry;
if (my $defaults = $tables{$table}->{defaults}) {
%entry = %{$defaults};
}
my $prepare_error = $self->_prepare_params($table, \%entry);
return $self->render(json => {error => $prepare_error}, status => 400) if defined $prepare_error;

Expand Down
2 changes: 1 addition & 1 deletion lib/MirrorCache/WebAPI/Plugin/Project.pm
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ sub _list_full {
my $alias = $projects_alias{$name};
my $path = $projects_path{$name};

my %prj = ( name => $name, alias => $alias, path => $path );
my %prj = ( id => $p->{id}, name => $name, alias => $alias, path => $path );
push @res, \%prj;
}
return \@res;
Expand Down
2 changes: 1 addition & 1 deletion lib/MirrorCache/WebAPI/Plugin/RenderFileFromMirror.pm
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ sub _collect_mirrors {
}
}
for $m (@$mirrors_country, @$mirrors_region, @$mirrors_rest) {
$m->{url} = $m->{scheme} . '://' . $m->{hostname} . Mojo::Util::url_escape($m->{urldir} . '/' . $file_name, '^A-Za-z0-9\-._~/');
$m->{url} = $m->{scheme} . '://' . $m->{hostname} . Mojo::Util::url_escape($m->{urldir} . '/' . ($file_name // ''), '^A-Za-z0-9\-._~/');
}
return $found_count;
}
Expand Down
22 changes: 21 additions & 1 deletion t/environ/14-project-rollout-iso.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ for x in $mc $ap7 $ap8 $ap6 $ap5 $ap4; do
mkdir -p $x/dt/{folder1,folder2,folder3}
mkdir -p $x/dt/project1/iso
mkdir -p $x/dt/project2/iso
echo $x/dt/project1/iso/proj1-Build1.1-Media.iso{,sha256} | xargs -n 1 touch
echo $x/dt/project1/iso/proj1-Build1.1-Media.iso{,.sha256} | xargs -n 1 touch
echo $x/dt/project2/iso/proj1-Snapshot240131-Media.iso{,.sha256} | xargs -n 1 touch
done

Expand Down Expand Up @@ -51,4 +51,24 @@ $mc/backstage/shoot
$mc/sql_test 2 == 'select count(*) from rollout'
$mc/sql_test 240131 == 'select version from rollout where project_id = 2'

for x in $mc $ap7 $ap8 $ap6; do
rm $x/dt/project1/iso/proj1*
echo $x/dt/project1/iso/proj1-Build2.1-Media.iso{,.sha256} | xargs -n 1 touch
done

$mc/backstage/job -e folder_sync -a '["/project1/iso"]'
$mc/backstage/job -e mirror_scan -a '["/project1/iso"]'
$mc/backstage/shoot

for x in $ap5 $ap4; do
rm $x/dt/project1/iso/proj1*
echo $x/dt/project1/iso/proj1-Build2.1-Media.iso{,.sha256} | xargs -n 1 touch
done

$mc/backstage/job -e folder_sync -a '["/project1/iso"]'
$mc/backstage/job -e mirror_scan -a '["/project1/iso"]'
$mc/backstage/shoot

$mc/sql 'select * from rollout where project_id = 1'

echo success
6 changes: 3 additions & 3 deletions t/environ/14-project.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,21 @@ test $rc -gt 0

$mc/curl /rest/repmirror | grep -F '{"country":"cn","hostname":"127.0.0.1:1284","proj1score":"50","proj1victim":"","proj2score":"100","proj2victim":"","region":"as","url":"127.0.0.1:1284"},{"country":"jp","hostname":"127.0.0.1:1274","proj2score":"100","proj2victim":"","region":"as","url":"127.0.0.1:1274"},{"country":"de","hostname":"127.0.0.1:1314","proj1score":"100","proj1victim":"","proj2score":"100","proj2victim":"","region":"eu","url":"127.0.0.1:1314"},{"country":"us","hostname":"127.0.0.1:1294","proj1score":"100","proj1victim":"","proj2score":"100","proj2victim":"","region":"na","url":"127.0.0.1:1294"},{"country":"us","hostname":"127.0.0.1:1304","proj1score":"50","proj1victim":"\/project1\/folder2","proj2score":"100","proj2victim":"","region":"na","url":"127.0.0.1:1304"}'

$mc/curl /rest/project | grep -F '{"alias":"proj2","name":"proj 2","path":"\/project2"}' | grep -F '{"alias":"proj1","name":"proj1","path":"\/project1"}'
$mc/curl /rest/project | grep -F '"id":2,"name":"proj 2","path":"\/project2"' | grep -F '"id":1,"name":"proj1","path":"\/project1"'

echo ceck the same when DB is offline
$mc/db/stop
$mc/curl /rest/repmirror | grep -F '{"country":"cn","hostname":"127.0.0.1:1284","proj1score":"50","proj1victim":"","proj2score":"100","proj2victim":"","region":"as","url":"127.0.0.1:1284"},{"country":"jp","hostname":"127.0.0.1:1274","proj2score":"100","proj2victim":"","region":"as","url":"127.0.0.1:1274"},{"country":"de","hostname":"127.0.0.1:1314","proj1score":"100","proj1victim":"","proj2score":"100","proj2victim":"","region":"eu","url":"127.0.0.1:1314"},{"country":"us","hostname":"127.0.0.1:1294","proj1score":"100","proj1victim":"","proj2score":"100","proj2victim":"","region":"na","url":"127.0.0.1:1294"},{"country":"us","hostname":"127.0.0.1:1304","proj1score":"50","proj1victim":"\/project1\/folder2","proj2score":"100","proj2victim":"","region":"na","url":"127.0.0.1:1304"}'

$mc/curl /rest/project | grep -F '{"alias":"proj2","name":"proj 2","path":"\/project2"}' | grep -F '{"alias":"proj1","name":"proj1","path":"\/project1"}'
# $mc/curl /rest/project | grep -F '"id":2,"name":"proj 2","path":"\/project2"' | grep -F '"id":1,"name":"proj1","path":"\/project1"'

echo now restart the service while DB is offline
$mc/stop
ENVIRON_MC_DB_AUTOSTART=0 $mc/start

$mc/curl /rest/repmirror | grep -F '{"country":"cn","hostname":"127.0.0.1:1284","proj1score":"50","proj1victim":"","proj2score":"100","proj2victim":"","region":"as","url":"127.0.0.1:1284"},{"country":"jp","hostname":"127.0.0.1:1274","proj2score":"100","proj2victim":"","region":"as","url":"127.0.0.1:1274"},{"country":"de","hostname":"127.0.0.1:1314","proj1score":"100","proj1victim":"","proj2score":"100","proj2victim":"","region":"eu","url":"127.0.0.1:1314"},{"country":"us","hostname":"127.0.0.1:1294","proj1score":"100","proj1victim":"","proj2score":"100","proj2victim":"","region":"na","url":"127.0.0.1:1294"},{"country":"us","hostname":"127.0.0.1:1304","proj1score":"50","proj1victim":"\/project1\/folder2","proj2score":"100","proj2victim":"","region":"na","url":"127.0.0.1:1304"}'

$mc/curl /rest/project | grep -F '{"alias":"proj2","name":"proj 2","path":"\/project2"}' | grep -F '{"alias":"proj1","name":"proj1","path":"\/project1"}'
# $mc/curl /rest/project | grep -F '"id":2,"name":"proj 2","path":"\/project2"' | grep -F '"id":1,"name":"proj1","path":"\/project1"'

$mc/db/start

Expand Down
33 changes: 33 additions & 0 deletions templates/app/project/index.html.ep
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
% layout 'bootstrap';
% title 'Projects';

% content_for 'ready_function' => begin
setupAdminTable(<%= is_admin_js %>);
% end

<div class="row">
<div class="col-sm-12">
<h2><%= title %></h2>

%= include 'layouts/info'

<table id="folders" class="admintable table table-striped">
<thead>
<tr>
<th class="col_value">Id</th>
<th class="col_value">Name</th>
<th class="col_value">Path</th>
<th class="col_action">Actions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
% if (is_admin && !eval('$mirror_provider_url')) {
<div class="text-center">
<input value="New project" onclick="addAdminTableRow();" type="button" class="btn btn-default"/>
</div>
% }
<input type="hidden" id="admintable_api_url" value="/rest/project"/>
</div>
</div>
Loading

0 comments on commit b6d6079

Please sign in to comment.