]>
git.proxmox.com Git - pve-manager.git/blob - PVE/API2/Tasks.pm
1 package PVE
:: API2
:: Tasks
;
7 use File
:: ReadBackwards
;
12 use PVE
:: RPCEnvironment
;
13 use PVE
:: JSONSchema
qw(get_standard_option) ;
14 use PVE
:: Exception
qw(raise_param_exc) ;
15 use PVE
:: AccessControl
;
17 use base
qw(PVE::RESTHandler) ;
19 my $convert_token_task = sub {
22 if ( PVE
:: AccessControl
:: pve_verify_tokenid
( $task ->{ user
}, 1 )) {
23 ( $task ->{ user
}, $task ->{ tokenid
}) = PVE
:: AccessControl
:: split_tokenid
( $task ->{ user
});
27 __PACKAGE__-
> register_method ({
32 description
=> "List task associated with the current user, or all task the user has 'Sys.Audit' permissions on /nodes/<node> (the <node> the task runs on)." ,
35 description
=> "Read task list for one node (finished tasks)." ,
38 additionalProperties
=> 0 ,
40 node
=> get_standard_option
( 'pve-node' ),
46 description
=> "List tasks beginning from this offset." ,
53 description
=> "Only list this amount of tasks." ,
58 description
=> "Only list tasks from this user." ,
63 description
=> 'Only list tasks of this type (e.g., vzstart, vzdump).' ,
65 vmid
=> get_standard_option
( 'pve-vmid' , {
66 description
=> "Only list tasks for this VM." ,
76 enum
=> [ 'archive' , 'active' , 'all' ],
79 description
=> 'List archived, active or all tasks.' ,
88 upid
=> { type
=> 'string' , title
=> 'UPID' , },
89 node
=> { type
=> 'string' , title
=> 'Node' , },
90 pid
=> { type
=> 'integer' , title
=> 'PID' , },
91 pstart
=> { type
=> 'integer' , },
92 starttime
=> { type
=> 'integer' , title
=> 'Starttime' , },
93 type
=> { type
=> 'string' , title
=> 'Type' , },
94 id
=> { type
=> 'string' , title
=> 'ID' , },
95 user
=> { type
=> 'string' , title
=> 'User' , },
96 endtime
=> { type
=> 'integer' , optional
=> 1 , title
=> 'Endtime' , },
97 status
=> { type
=> 'string' , optional
=> 1 , title
=> 'Status' , },
100 links
=> [ { rel
=> 'child' , href
=> "{upid}" } ],
105 my $rpcenv = PVE
:: RPCEnvironment
:: get
();
106 my $user = $rpcenv -> get_user ();
110 my $filename = "/var/log/pve/tasks/index" ;
112 my $node = $param ->{ node
};
113 my $start = $param ->{ start
} // 0 ;
114 my $limit = $param ->{ limit
} // 50 ;
115 my $userfilter = $param ->{ userfilter
};
116 my $typefilter = $param ->{ typefilter
};
117 my $errors = $param ->{ errors
} // 0 ;
118 my $source = $param ->{ source
} // 'archive' ;
123 my $auditor = $rpcenv -> check ( $user, "/nodes/ $node " , [ 'Sys.Audit' ], 1 );
125 my $filter_task = sub {
128 return 1 if $userfilter && $task ->{ user
} !~ m/\Q$userfilter\E/i ;
129 return 1 if !( $auditor || $user eq $task ->{ user
});
131 return 1 if $typefilter && $task ->{ type
} ne $typefilter ;
133 return 1 if $errors && $task ->{ status
} && $task ->{ status
} eq 'OK' ;
134 return 1 if $param ->{ vmid
} && (! $task ->{ id
} || $task ->{ id
} ne $param ->{ vmid
});
136 return 1 if $count++ < $start ;
137 return 1 if $limit <= 0 ;
142 my $parse_line = sub {
143 if ( $line =~ m/^(\S+)(\s([0-9A-Za-z]{8})(\s(\S.*))?)?$/ ) {
147 if (( my $task = PVE
:: Tools
:: upid_decode
( $upid, 1 ))) {
149 $task ->{ upid
} = $upid ;
150 $task ->{ endtime
} = hex ( $endtime ) if $endtime ;
151 $task ->{ status
} = $status if $status ;
153 $convert_token_task ->( $task );
154 if (! $filter_task ->( $task )) {
162 if ( $source eq 'active' || $source eq 'all' ) {
163 my $recent_tasks = PVE
:: INotify
:: read_file
( 'active' );
164 for my $task ( @$recent_tasks ) {
165 next if $task ->{ saved
}; # archived task, already in index(.1)
166 if (! $filter_task ->( $task )) {
167 $task ->{ status
} = 'RUNNING' if ! $task ->{ status
}; # otherwise it would be archived
174 if ( $source ne 'active' ) {
175 if ( my $bw = File
:: ReadBackwards-
> new ( $filename )) {
176 while ( defined ( $line = $bw -> readline )) {
181 if ( my $bw = File
:: ReadBackwards-
> new ( " $filename .1" )) {
182 while ( defined ( $line = $bw -> readline )) {
189 $rpcenv -> set_result_attrib ( 'total' , $count );
194 __PACKAGE__-
> register_method ({
195 name
=> 'upid_index' ,
198 description
=> '' , # index helper
199 permissions
=> { user
=> 'all' },
201 additionalProperties
=> 0 ,
203 node
=> get_standard_option
( 'pve-node' ),
204 upid
=> { type
=> 'string' },
213 links
=> [ { rel
=> 'child' , href
=> "{name}" } ],
224 __PACKAGE__-
> register_method ({
228 description
=> 'Stop a task.' ,
230 description
=> "The user needs 'Sys.Modify' permissions on '/nodes/<node>' if the task does not belong to him." ,
236 additionalProperties
=> 0 ,
238 node
=> get_standard_option
( 'pve-node' ),
239 upid
=> { type
=> 'string' },
242 returns
=> { type
=> 'null' },
246 my ( $task, $filename ) = PVE
:: Tools
:: upid_decode
( $param ->{ upid
}, 1 );
247 raise_param_exc
({ upid
=> "unable to parse worker upid" }) if ! $task ;
248 raise_param_exc
({ upid
=> "no such task" }) if ! - f
$filename ;
250 my $rpcenv = PVE
:: RPCEnvironment
:: get
();
251 my $user = $rpcenv -> get_user ();
252 my $node = $param ->{ node
};
254 $convert_token_task ->( $task );
256 if ( $user ne $task ->{ user
}) {
257 $rpcenv -> check ( $user, "/nodes/ $node " , [ 'Sys.Modify' ]);
260 PVE
:: RPCEnvironment-
> check_worker ( $param ->{ upid
}, 1 );
265 __PACKAGE__-
> register_method ({
266 name
=> 'read_task_log' ,
267 path
=> '{upid}/log' ,
270 description
=> "The user needs 'Sys.Audit' permissions on '/nodes/<node>' if the task does not belong to him." ,
274 description
=> "Read task log." ,
277 additionalProperties
=> 0 ,
279 node
=> get_standard_option
( 'pve-node' ),
280 upid
=> { type
=> 'string' },
301 description
=> "Line number" ,
305 description
=> "Line text" ,
314 my ( $task, $filename ) = PVE
:: Tools
:: upid_decode
( $param ->{ upid
}, 1 );
315 raise_param_exc
({ upid
=> "unable to parse worker upid" }) if ! $task ;
317 my $rpcenv = PVE
:: RPCEnvironment
:: get
();
318 my $user = $rpcenv -> get_user ();
319 my $node = $param ->{ node
};
320 my $start = $param ->{ start
} // 0 ;
321 my $limit = $param ->{ limit
} // 50 ;
323 $convert_token_task ->( $task );
325 if ( $user ne $task ->{ user
}) {
326 $rpcenv -> check ( $user, "/nodes/ $node " , [ 'Sys.Audit' ]);
329 my ( $count, $lines ) = PVE
:: Tools
:: dump_logfile
( $filename, $start, $limit );
331 $rpcenv -> set_result_attrib ( 'total' , $count );
337 my $exit_status_cache = {};
339 __PACKAGE__-
> register_method ({
340 name
=> 'read_task_status' ,
341 path
=> '{upid}/status' ,
344 description
=> "The user needs 'Sys.Audit' permissions on '/nodes/<node>' if the task does not belong to him." ,
348 description
=> "Read task status." ,
351 additionalProperties
=> 0 ,
353 node
=> get_standard_option
( 'pve-node' ),
354 upid
=> { type
=> 'string' },
364 type
=> 'string' , enum
=> [ 'running' , 'stopped' ],
371 my ( $task, $filename ) = PVE
:: Tools
:: upid_decode
( $param ->{ upid
}, 1 );
372 raise_param_exc
({ upid
=> "unable to parse worker upid" }) if ! $task ;
373 raise_param_exc
({ upid
=> "no such task" }) if ! - f
$filename ;
377 my $rpcenv = PVE
:: RPCEnvironment
:: get
();
378 my $user = $rpcenv -> get_user ();
379 my $node = $param ->{ node
};
381 $convert_token_task ->( $task );
383 if ( $user ne $task ->{ user
}) {
384 $rpcenv -> check ( $user, "/nodes/ $node " , [ 'Sys.Audit' ]);
387 my $pstart = PVE
:: ProcFSTools
:: read_proc_starttime
( $task ->{ pid
});
388 $task ->{ status
} = ( $pstart && ( $pstart == $task ->{ pstart
})) ?
389 'running' : 'stopped' ;
391 $task ->{ upid
} = $param ->{ upid
}; # include upid
393 if ( $task ->{ status
} eq 'stopped' ) {
394 if (! defined ( $exit_status_cache ->{ $task ->{ upid
}})) {
395 $exit_status_cache ->{ $task ->{ upid
}} =
396 PVE
:: Tools
:: upid_read_status
( $task ->{ upid
});
398 $task ->{ exitstatus
} = $exit_status_cache ->{ $task ->{ upid
}};