Skip to content

[DEVEL] Create new action request

Francesc Guasch edited this page Nov 30, 2020 · 2 revisions

The Ravada frontend and backend processes talk to each other through Ravada Requests. These are stored in a Database on creation. The backend checks for new requests to run.

In this example we take a simplified version of the shutdown procedure to see how it could have been implemented. Notice the real shutdown is more complicated with more checks and code, but this should be enough to get started.

Define a Request

Create the new request in the file lib/Ravada/Request.pm

A basic request only needs the parameter definition. More demanding request run some code before being created.

Basic Request

Define the request in the file lib/Ravada/Request.pm in the %VALID_ARG hash. Example:

shutdown => { uid => 1
                   , id_domain => 2
                   , name => 2
                   , timeout => 2
                   , at => 2
}

In this example uid is mandatory argument so we tag it with a "1", the other arguments are optional so a "2" is given to them.

That definition it is enough so the front end can create new requests this way:

Ravada::Request->shutdown( uid => $user->id, id_domain => $id_domain )

Advanced Request

You can create a new method with the name of the request in lib/Ravada/Request.pm . Maybe to check the validity of the arguments or something else. If all is fine, in the end run this code to finally create the request in the database:

sub shutdown {
    my $proto = shift;
    my $class=ref($proto) || $proto;
    
    my $args = _check_args('shutdown', @_ );
    
    confess "ERROR: You must supply either id_domain or name ".Dumper($args)
    if !$args->{id_domain} && !$args->{name};
    
    my $self = {};
    bless($self,$class);
    
    return $self->_new_request(command => 'shutdown' , args => $args);
}

Run the request

To run the request add a method in lib/Ravada.pm. Also add an entry in sub _req_method do define what method will be run for each request:

  my %methods = (
  ...
  ,shutdown => \&_cmd_shutdown

When shutdown is executed it will run the method _cmd_shutdown in lib/Ravada.pm. It would be something like this:

sub _cmd_shutdown($self, $request) {
    my $uid = $request->args('uid');
    my $timeout = ($request->args('timeout') or 60);
    my $name = $request->defined_arg('name');
    my $id_domain = $request->defined_arg('id_domain');

    my $domain;
    $domain = Ravada::Domain->open($id_domain) if $id_domain;
    $domain = $self->search_domain($name)      if $name;
    die "Error: No domain ".($id_domain or $name) if !$domain;
    
    my $user = Ravada::Auth::SQL->search_by_id($uid);
    
    die "Error: user ".$user->name." is not allowed to shutdown ".$domain->name
    unless $user->is_operator || $domain->_data('id_owner') == $uid;

    $domain->shutdown(timeout => $timeout, user => $user);
}

Implement the method

The final step of the request is executing the shutdown method in the virtual machine. To do so create the method in lib/Ravada/Domain/KVM.pm

In this case we use the Sys::Virt::Domain object that has a shutdown method we can call.

sub shutdown($self, %args) {
    my $timeout = delete $args{timeout};
    $self->domain->shutdown();
    
 }

Method modifiers

We can add modifiers for all the methods, in our example we force a shutdown if the timeout argument has been requested. Add this to lib/Ravada/Domain.pm

before 'shutdown' => \&_pre_shutdown
 after 'shutdown' => \&_post_shutdown

After the shutdown is executed this code will be run for any kind of virtual machines. We call another request to force the shutdown if the timeout argument has been passed.

sub _pre_shutdown($self, %args) {
    ... check some stuff
}

sub _post_shutdown($self, %args) {
    my $timeout = delete $args{timeout};
    my $user = delete $args{user};

    Ravada::Request->force_shutdown(         uid => $user->id
                                            , at => time+60
                                     , id_domain => $self->id
    )
    if $timeout;
}
Clone this wiki locally