Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature network management #1984

Merged
merged 64 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
ad2839e
wip: turn network into routes and new virtual networks
frankiejol Jul 17, 2023
9b0deb5
wip: rename network to route
frankiejol Jul 17, 2023
b2b41c1
wip: network management
frankiejol Jul 21, 2023
e4b554e
wip: frontend manage virtual networks
frankiejol Jul 24, 2023
d39f5f9
wip: list networks
frankiejol Jul 24, 2023
53f84d2
wip: change network
frankiejol Jul 24, 2023
06a6e45
wip: change and remove network
frankiejol Jul 26, 2023
5a9d2a3
wip: create network
frankiejol Jul 27, 2023
15a9676
wip: update network changes in db
frankiejol Jul 28, 2023
ea2b714
wip: new network
frankiejol Jul 28, 2023
f40f47f
wip: networks management
frankiejol Sep 14, 2023
3715582
wip: generic network management
frankiejol Sep 14, 2023
b4f907c
wip: new network
frankiejol Sep 18, 2023
8533dc3
wip: manage networks
frankiejol Sep 18, 2023
8f46a7f
wip: manage virtual networks
frankiejol Sep 18, 2023
e326f55
Merge branch 'main' into feature/network
frankiejol Sep 18, 2023
1cc92e3
wip: properly test routes
frankiejol Sep 18, 2023
48bd962
wip: test networks mojo
frankiejol Sep 19, 2023
10d1405
wip: allow optional new network name
frankiejol Sep 19, 2023
6817bc6
wip: grant manager networks
frankiejol Sep 20, 2023
50ede96
wip: test networks access
frankiejol Sep 20, 2023
211ff7a
wip: check auth to manage networks
frankiejol Sep 20, 2023
7e0a2cc
wip: test admin networks
frankiejol Sep 21, 2023
0aab6ee
wip: remove networks when removing user and testing
frankiejol Sep 21, 2023
d709d03
wip: public networks
frankiejol Sep 22, 2023
77c74bf
wip: enforce access to networks
frankiejol Sep 22, 2023
da6f7b0
wip: grant access to manage networks
frankiejol Sep 26, 2023
9366414
wip: removed extra quote
frankiejol Sep 26, 2023
8b23a8f
wip: do not activate if no found
frankiejol Sep 26, 2023
19af3c4
wip: properly change networks
frankiejol Sep 27, 2023
66ff07a
wip: allow change machine network
frankiejol Sep 27, 2023
38bd20b
wip: grant manage all networks
frankiejol Sep 27, 2023
59371f2
wip: properly check owner
frankiejol Sep 27, 2023
4480214
wip: removed debug
frankiejol Sep 27, 2023
12c3901
wip: anonymous access
frankiejol Sep 27, 2023
0c32131
wip: fixed anonymous login
frankiejol Sep 28, 2023
6cd5a97
wip: work around not found counter
frankiejol Sep 28, 2023
4327f83
wip: doc for can change hw network
frankiejol Sep 28, 2023
b429839
wip: doc list networks in front
frankiejol Sep 28, 2023
548ffe6
wip: test networks
frankiejol Sep 28, 2023
57f57c5
wip: make sure nw doesn't get deleted before change
frankiejol Sep 28, 2023
df444c8
wip: keep trying to pass tests in github
frankiejol Sep 28, 2023
f56c880
wip: remove only current test networks
frankiejol Sep 28, 2023
df86372
wip: properly get test nat networks
frankiejol Sep 29, 2023
f73ab92
wip(test): clean test hwadress
frankiejol Sep 29, 2023
b7a7af1
wip: do not remove when mock vm
frankiejol Oct 2, 2023
bd74468
Merge branch 'main' into feature/network
frankiejol Oct 27, 2023
354b2ad
Merge branch 'main' into feature/network
frankiejol Nov 3, 2023
da0d0fc
wip: removed all around method
frankiejol Nov 3, 2023
bb98ade
wip: do not show selection when no permission
frankiejol Nov 6, 2023
7273a26
wip: test virtual machine network
frankiejol Nov 7, 2023
8714192
Merge branch 'feature/network' of github.com:UPC/ravada into feature/…
frankiejol Nov 7, 2023
d110dc6
wip: doc list files
frankiejol Nov 7, 2023
40490f4
wip: remove old id entries
frankiejol Nov 7, 2023
0368145
wip: clean mock networks
frankiejol Nov 8, 2023
1b65454
wip: removed debug
frankiejol Nov 8, 2023
5a2d8af
wip: create dir the very first time
frankiejol Nov 8, 2023
3b3f32f
wip: correctly select an active VM
frankiejol Nov 28, 2023
42f5be4
wip: network options
frankiejol Jan 22, 2024
545b494
test: assign network
frankiejol Jan 22, 2024
f028d48
wip(frontend): manage network
frankiejol Jan 22, 2024
6baee9e
Merge branch 'main' into feature/network
frankiejol Jan 22, 2024
407c1f0
wip: removed unused width
frankiejol Jan 22, 2024
f609a5e
Merge branch 'feature/network' of github.com:UPC/ravada into feature/…
frankiejol Jan 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 140 additions & 1 deletion lib/Ravada.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1641,6 +1641,12 @@ sub _add_indexes_generic($self) {
,"UNIQUE (name)"

]
,virtual_networks => [
"unique(id_vm,internal_id)"
,"unique(id_vm,name)"
,"index(date_changed)"
,"index(id_owner)"
]
);
my $if_not_exists = '';
$if_not_exists = ' IF NOT EXISTS ' if $CONNECTOR->dbh->{Driver}{Name} =~ /sqlite|mariadb/i;
Expand Down Expand Up @@ -1812,6 +1818,8 @@ sub _add_grants($self) {
$self->_add_grant('view_all',0,"The user can start and access the screen of any virtual machine");
$self->_add_grant('create_disk',0,'can create disk volumes');
$self->_add_grant('quota_disk',0,'disk space limit',1);
$self->_add_grant('create_networks',0,'can create virtual networks.');
$self->_add_grant('manage_all_networks',0,'can manage all the virtual networks.');
}

sub _add_grant($self, $grant, $allowed, $description, $is_int = 0, $default_admin=1) {
Expand Down Expand Up @@ -1889,6 +1897,7 @@ sub _enable_grants($self) {
,'start_limit', 'start_many'
,'view_all'
,'create_disk', 'quota_disk'
,'create_networks','manage_all_networks'
);

my $sth = $CONNECTOR->dbh->prepare("SELECT id,name FROM grant_types");
Expand Down Expand Up @@ -2362,6 +2371,24 @@ sub _sql_create_tables($self) {

}
]
,
[virtual_networks => {
id => 'integer PRIMARY KEY AUTO_INCREMENT',
,id_vm => 'integer NOT NULL references `vms` (`id`) ON DELETE CASCADE',
,name => 'varchar(200)'
,id_owner => 'integer NOT NULL references `users` (`id`) ON DELETE CASCADE',
,internal_id => 'char(80) not null'
,autostart => 'integer not null'
,bridge => 'char(80)'
,'ip_address' => 'char(20)'
,'ip_netmask' => 'char(20)'
,'dhcp_start' => 'char(15)'
,'dhcp_end' => 'char(15)'
,'is_active' => 'integer not null default 1'
,'is_public' => 'integer not null default 0'
,date_changed => 'timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'
}
]

);
for my $new_table (@tables ) {
Expand Down Expand Up @@ -5111,7 +5138,12 @@ sub _cmd_change_hardware {
my $user = Ravada::Auth::SQL->search_by_id($uid);

die "Error: User ".$user->name." not allowed\n"
if $hardware ne 'memory' && !$user->is_admin;
unless $user->is_admin
|| $hardware eq 'memory'
|| ($hardware eq 'network'
&& $user->can_change_hardware_network($domain, $data)
)
;

$domain->change_hardware(
$request->args('hardware')
Expand Down Expand Up @@ -5810,6 +5842,7 @@ sub _refresh_active_vms ($self) {
next;
}
$active_vm{$vm->id} = 1;
$vm->list_virtual_networks();
}
return \%active_vm;
}
Expand Down Expand Up @@ -6304,6 +6337,12 @@ sub _req_method {
,move_volume => \&_cmd_move_volume
,update_iso_urls => \&_cmd_update_iso_urls

,list_networks => \&_cmd_list_virtual_networks
,new_network => \&_cmd_new_network
,create_network => \&_cmd_create_network
,remove_network => \&_cmd_remove_network
,change_network => \&_cmd_change_network

);
return $methods{$cmd};
}
Expand Down Expand Up @@ -6723,6 +6762,106 @@ sub _cmd_remove_files($self, $request) {
$vm->remove_file(@file);
}

sub _cmd_list_virtual_networks($self, $request) {
my $user=Ravada::Auth::SQL->search_by_id($request->args('uid'));
die "Error: ".$user->name." not authorized\n"
unless $user->is_admin || $user->can_manage_all_networks || $user->can_create_networks;

my $id = $request->args('id_vm') or die "Error: missing id_vm";
my $vm = Ravada::VM->open($id);
my @list = $vm->list_virtual_networks();

$request->output(encode_json(\@list));
}


sub _cmd_new_network($self, $request) {
my $user=Ravada::Auth::SQL->search_by_id($request->args('uid'));
die "Error: ".$user->name." not authorized\n"
unless $user->can_create_networks;

$request->output(encode_json({}));

my $id = $request->args('id_vm') or die "Error: missing id_vm";
my $vm = Ravada::VM->open($id);
my $name = ($request->defined_arg('name') or 'net');

my $new = $vm->new_network($name);
$new = {} if !$new;

$request->output(encode_json( $new));
}

sub _cmd_create_network($self, $request) {
my $user=Ravada::Auth::SQL->search_by_id($request->args('uid'));
die "Error: ".$user->name." not authorized\n"
unless $user->can_create_networks || $user->can_manage_all_networks;

my $id = $request->args('id_vm') or die "Error: missing id_vm";
my $vm = Ravada::VM->open($id);
$request->output(encode_json({}));
my $id_net = $vm->create_network($request->args('data'),$request->args('uid')
, $request);
$request->output(encode_json({id_network => $id_net}));
}

sub _cmd_remove_network($self, $request) {

my $id = $request->args('id');
my $name = $request->defined_arg('name');
my $sth_net = $CONNECTOR->dbh->prepare(
"SELECT * FROM virtual_networks WHERE id=?"
);
$sth_net->execute($id);
my $network = $sth_net->fetchrow_hashref;
if ($network && $network->{id} ) {
_check_user_authorized_network($request, $id);
}
my $id_vm = ( $network->{id_vm} or $request->defined_arg('id_vm') );
die "Error: unknown id_vm ".Dumper([$network,$request]) if !$id_vm;

die "Error: unkonwn network , id=$id, name='".($name or '')."' "
.Dumper($network) if ! $network->{id} && !$name;

my $user=Ravada::Auth::SQL->search_by_id($request->args('uid'));

my $vm = Ravada::VM->open($id_vm);
$vm->remove_network($user, ($network->{id} or $name));
}

sub _check_user_authorized_network($request, $id_network) {

my $user=Ravada::Auth::SQL->search_by_id($request->args('uid'));

my $sth = $CONNECTOR->dbh->prepare(
"SELECT * FROM virtual_networks WHERE id=?"
);
$sth->execute($id_network);
my $network = $sth->fetchrow_hashref;

confess "Error: network $id_network not found" if !$network->{id};

die "Error: ".$user->name." not authorized\n"
unless $user->is_admin
|| $user->can_manage_all_networks
|| ( $user->can_create_networks && $network->{id_owner} == $user->id);

return $network;
}

sub _cmd_change_network($self, $request) {

my $data = $request->args('data');
die "Error: network.id required" if !exists $data->{id} || !$data->{id};

my $network = _check_user_authorized_network($request, $data->{id});

$data->{internal_id} = $network->{internal_id} if !$data->{internal_id};
my $vm = Ravada::VM->open($network->{id_vm});

$vm->change_network($data, $request->args('uid'));
}

sub _cmd_active_storage_pool($self, $request) {
my $user = Ravada::Auth::SQL->search_by_id($request->args('uid'));
die "Error: ".$user->name." not authorized to manage storage pools"
Expand Down
57 changes: 57 additions & 0 deletions lib/Ravada/Auth/SQL.pm
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ sub is_operator {
|| $self->can_view_groups()
|| $self->can_manage_groups()
|| $self->can_view_all()
|| $self->can_create_networks()
;
return 0;
}
Expand Down Expand Up @@ -635,9 +636,25 @@ sub remove($self) {
my $sth = $$CON->dbh->prepare("DELETE FROM grants_user where id_user=?");
$sth->execute($self->id);

$self->_remove_networks();

$sth = $$CON->dbh->prepare("DELETE FROM users where id=?");
$sth->execute($self->id);
$sth->finish;

}

sub _remove_networks($self) {
my $sth = $$CON->dbh->prepare("SELECT id,id_vm,name FROM virtual_networks WHERE id_owner=?");
$sth->execute($self->id);
while (my ($id, $id_vm, $name) = $sth->fetchrow) {
Ravada::Request->remove_network(
uid => Ravada::Utils::user_daemon->id
,id_vm => $id_vm
,id => $id
,name => $name
);
}
}

=head2 can_do
Expand Down Expand Up @@ -1235,6 +1252,46 @@ sub disk_used($self) {
return $used;
}

sub _load_network($network) {
confess "Error: undefined network"
if !defined $network;

my $sth = $$CON->dbh->prepare(
"SELECT * FROM virtual_networks where name=?"
);
$sth->execute($network);
my $row = $sth->fetchrow_hashref;

die "Error: network '$network' not found"
if !$row->{id};

lock_hash(%$row);
return $row;
}

=head2 can_change_hardware_network

Returns true if the user can change the network in a virtual machine,
false elsewhere

=cut

sub can_change_hardware_network($user, $domain, $data) {
return 1 if $user->is_admin;
return 1 if $user->can_manage_all_networks()
&& $domain->id_owner == $user->id;

confess "Error: undefined network ".Dumper($data)
if !exists $data->{network} || !defined $data->{network};

my $net = _load_network($data->{network});

return 1 if $user->id == $domain->id_owner
&& ( $net->{is_public} || $user->id == $net->{id_owner});
return 0;
}


sub AUTOLOAD($self, $domain=undef) {

my $name = $AUTOLOAD;
Expand Down
2 changes: 1 addition & 1 deletion lib/Ravada/Domain.pm
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ sub _around_start($orig, $self, @arg) {
if ( Ravada::setting(undef,"/backend/display_password") ) {
# We'll see if we set it from the network, defaults to 0 meanwhile
my $set_password = 0;
my $network = Ravada::Network->new(address => $remote_ip);
my $network = Ravada::Route->new(address => $remote_ip);
$set_password = 1 if $network->requires_password();
$arg{set_password} = $set_password;
}
Expand Down
22 changes: 20 additions & 2 deletions lib/Ravada/Domain/Void.pm
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,8 @@ sub _set_default_info($self, $listen_ip=undef) {
hwaddr => $info->{mac}
,address => $info->{ip}
,type => 'nat'
,driver => 'virtio'
,name => "net1"
};
$self->_store(hardware => $hardware );

Expand Down Expand Up @@ -921,6 +923,18 @@ sub _internal_autostart {
return $self->_value('autostart');
}

sub _new_network($self) {
my $hardware = $self->_value('hardware');
my $list = ( $hardware->{'network'} or [] );
my $data = {
hwaddr => _new_mac()
,address => ''
,type => 'nat'
,driver => 'virtio'
,name => "net".(scalar(@$list)+1)
};
}

sub set_controller($self, $name, $number=undef, $data=undef) {
my $hardware = $self->_value('hardware');

Expand All @@ -939,12 +953,16 @@ sub set_controller($self, $name, $number=undef, $data=undef) {
my @list2;
if (!defined $number) {
@list2 = @$list;
push @list2,($data or " $name z 1");
$data = $self->_new_network() if $name eq 'network' && !$data;
push @list2,($data or "$name z 1");
} else {
my $count = 0;
for my $item ( @$list ) {
$count++;
if ($number == $count) {
$data = $self->_new_network()
if $name eq 'network' && (!$data || ! keys %$data);

my $data2 = ( $data or " $name a ".($count+1));
$data2 = " $name b ".($count+1) if defined $data2 && ref($data2) && !keys %$data2;

Expand All @@ -953,7 +971,7 @@ sub set_controller($self, $name, $number=undef, $data=undef) {
}
$item = { driver => 'spice' , port => 'auto' , listen_ip => $self->_vm->listen_ip }
if $name eq 'display' && !defined $item;
push @list2,($item or " $name b ".($count+1));
push @list2,($item or " $name c ".($count+1));
}
}
$hardware->{$name} = \@list2;
Expand Down
Loading
Loading