(* mclu: Mini Cloud * Copyright (C) 2014-2015 Red Hat Inc. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) (* Implement 'mclu on' and 'mclu off'. *) open Printf open Utils let get_arg_speclist () = Arg.align [ ] let wake ~verbose nodes = let wol = match Config.path_wol with | Some wol -> wol | None -> eprintf "mclu: Wake-on-LAN is not available Recompile mclu with the 'wol' program installed\n"; exit 1 in (* Only wake nodes which are switched off. *) let nodes = List.filter (fun { Mclu_status.node_on = on } -> not on) nodes in let nodes = List.map (fun { Mclu_status.node = node } -> node) nodes in List.iter ( function | { Mclu_conf.mac_addr = Some mac_addr } -> let cmd = sprintf "%s %s" (quote wol) (quote mac_addr) in if verbose then printf "%s\n%!" cmd; if Sys.command cmd <> 0 then ( eprintf "mclu: wol: command failed\n"; exit 1 ) | { Mclu_conf.hostname = hostname; mac_addr = None } -> eprintf "mclu: Wake-on-LAN is not configured for node %s Edit mclu.conf and add 'mac=' to this host line.\n" hostname; exit 1 ) nodes let shutdown ~verbose nodes = (* Only shutdown nodes which are switched on. *) let nodes = List.filter (fun { Mclu_status.node_on = on } -> on) nodes in let nodes = List.map (fun { Mclu_status.node = node } -> node) nodes in (* Get the active guests on these nodes. *) let active_guests = Mclu_list.active_guests ~verbose ~nodes () in let errors = ref 0 in List.iter ( fun ({ Mclu_conf.hostname = hostname } as node) -> let guests = try List.assoc node active_guests with Not_found -> [] in if guests <> [] then ( eprintf "mclu: node %s has %d guest(s) running: %s Shut down these guests before turning off the node.\n" hostname (List.length guests) (String.concat ", " (List.map (fun guest -> guest.Mclu_list.dom_name) guests)); incr errors ) else ( (* We have to be cunning about this else ssh will return an error. *) let cmd = sprintf "ssh -o ForwardX11=no root@%s '(sleep 5; poweroff) /dev/null 2>&1 &'" (quote hostname) in if verbose then printf "%s\n%!" cmd; if Sys.command cmd <> 0 then ( eprintf "mclu: %s: poweroff: command failed\n" hostname; incr errors ) ) ) nodes; if !errors > 0 then exit 1 let expand_wildcards exprs = let regexps = List.map regexp_of_glob exprs in let regexps = List.map Pcre.regexp regexps in let nodes = Mclu_status.node_statuses () in let nodes = List.filter ( fun { Mclu_status.node = { Mclu_conf.hostname = hostname } } -> List.exists (fun rex -> Pcre.pmatch ~rex hostname) regexps ) nodes in if List.length nodes < List.length exprs then ( eprintf "mclu: [on|off]: some wildcards don't match hostnames\n"; exit 1 ); nodes let run ~verbose ~on = function | (_::_) as xs -> let nodes = expand_wildcards xs in (if on then wake else shutdown) ~verbose nodes | [] -> eprintf "Usage: mclu [on|off] node|wildcard ...\n"; exit 1