[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-API] [PATCH 13 of 21] CP-1841: add new api call vmpp.get_alerts



 ocaml/idl/datamodel.ml                |  12 ++++++
 ocaml/idl/ocaml_backend/rbac_audit.ml |  26 ++++---------
 ocaml/xapi/audit_log.ml               |  22 +++++++++--
 ocaml/xapi/xapi_vm_clone.ml           |   2 +-
 ocaml/xapi/xapi_vmpp.ml               |  64 +++++++++++++++++++++++++++++++++++
 scripts/mail-alarm                    |  28 ++++++++++++++-
 6 files changed, 129 insertions(+), 25 deletions(-)


# HG changeset patch
# User Marcus Granado <marcus.granado@xxxxxxxxxx>
# Date 1282322886 -3600
# Node ID 69e3ee3fb691d14532504fa5014451a9fad58be6
# Parent  f8298e1caacd3a2a5323388ac9d44a4ae12bf98d
CP-1841: add new api call vmpp.get_alerts

Signed-off-by: Marcus Granado <marcus.granado@xxxxxxxxxxxxx>

diff -r f8298e1caacd -r 69e3ee3fb691 ocaml/idl/datamodel.ml
--- a/ocaml/idl/datamodel.ml
+++ b/ocaml/idl/datamodel.ml
@@ -5875,6 +5875,17 @@
   ~allowed_roles:_R_VM_POWER_ADMIN
   ~result:(String, "An XMLRPC result")
   ()
+let vmpp_get_alerts = call ~flags:[`Session]
+  ~name:"get_alerts"
+  ~in_oss_since:None
+  ~in_product_since:rel_cowley
+  ~params:[Ref _vmpp, "vmpp", "The protection policy";
+    DateTime, "since", "oldest record to fetch";
+  ]
+  ~doc:"This call fetches a history of alerts for a given protection policy"
+  ~allowed_roles:_R_POOL_OP
+  ~result:(Set (String), "A list of alerts encoded in xml")
+  ()
 let vmpp_backup_type = Enum ("vmpp_backup_type",
   [
     "snapshot", "The backup is a snapshot";
@@ -6105,6 +6116,7 @@
     ~messages:[
       vmpp_protect_now;
       vmpp_archive_now;
+      vmpp_get_alerts;
       vmpp_set_is_backup_running;
       vmpp_set_is_archive_running;
       vmpp_set_backup_frequency;
diff -r f8298e1caacd -r 69e3ee3fb691 ocaml/idl/ocaml_backend/rbac_audit.ml
--- a/ocaml/idl/ocaml_backend/rbac_audit.ml
+++ b/ocaml/idl/ocaml_backend/rbac_audit.ml
@@ -81,26 +81,14 @@
 let get_subject_name __context session_id =
        get_subject_common ~__context ~session_id
                ~fnname:"get_subject_name"
-               ~fn_if_local_session:(fun()->"")
-               ~fn_if_local_superuser:(fun()->"")
+               ~fn_if_local_session:(fun()->
+                               DB_Action.Session.get_auth_user_name ~__context 
~self:session_id
+               )
+               ~fn_if_local_superuser:(fun()->
+                               DB_Action.Session.get_auth_user_name ~__context 
~self:session_id
+               )
                ~fn_if_subject:(fun()->
                                DB_Action.Session.get_auth_user_name ~__context 
~self:session_id
-                       (*
-                       let sid =
-                               DB_Action.Session.get_auth_user_sid ~__context 
~self:session_id
-                       in
-                       let subjs = DB_Action.Subject.get_records_where 
~__context
-                               ~expr:(Eq(Field "subject_identifier", Literal 
(sid)))
-                       in
-                       if List.length subjs > 1 then
-                               failwith (Printf.sprintf
-                                       "More than one subject for 
subject_identifier %s"sid
-                               );
-                       let (subj_id,subj) = List.hd subjs in
-                       List.assoc
-                               "subject-name" 
(*Auth_signature.subject_information_field_subject_name*)
-                               subj.API.subject_other_config
-                       *)
                )
 
 (*given a ref-value, return a human-friendly value associated with that ref*)
@@ -209,6 +197,8 @@
                ("host.enable_external_auth",["service_name";"auth_type"]);
                ("subject.create",["subject_identifier";"other_config"]);
                ("subject.create.other_config",["subject-name"]);
+    (* used for VMPP alert logs *)
+    ("message.create",["name";"body"]);
        ]
 
 (* manual ref getters *)
diff -r f8298e1caacd -r 69e3ee3fb691 ocaml/xapi/audit_log.ml
--- a/ocaml/xapi/audit_log.ml
+++ b/ocaml/xapi/audit_log.ml
@@ -26,7 +26,16 @@
 let timestamp_index line = 
        try ((String.index line '[') + 1) with Not_found -> 0
 
-let write_line line fd since =
+let went_through ?filter line =
+       match filter with
+       |None->true
+       |Some fs->
+                List.fold_left
+                        (fun acc f->acc&&(String.has_substr line f))
+                        true
+       fs
+
+let write_line line fd ?filter since =
        if String.length line >
                (line_timestamp_length + (timestamp_index line))
        then
@@ -35,10 +44,12 @@
        in
        if since="" or ((String.compare line_timestamp since) >= 0)
        then
+       if went_through ?filter line
+  then
        let len = String.length line in
        ignore(Unix.write fd line 0 len)
 
-let transfer_audit_file _path compression fd_out since =
+let transfer_audit_file _path compression fd_out ?filter since =
        let path = Unixext.resolve_dot_and_dotdot _path in
        let in_whitelist = (String.startswith audit_log_whitelist_prefix path) 
in
        if in_whitelist then
@@ -50,7 +61,7 @@
                        if compression="" (* uncompressed *)
                        then begin
                                Unixext.readfile_line
-                                       (fun line -> write_line (line^"\n") 
fd_out since)
+                                       (fun line -> write_line (line^"\n") 
fd_out ?filter since)
                                        path
                        end
                        else if compression="gz"
@@ -63,7 +74,7 @@
                                                                try
                                                                        while 
true do
                                                                                
let line = input_line cin in
-                                                                               
write_line (line^"\n") fd_out since
+                                                                               
write_line (line^"\n") fd_out ?filter since
                                                                        done
                                                                with 
End_of_file -> () (* ok, expected *)
                                                        )
@@ -79,7 +90,7 @@
                end
        end
 
-let transfer_all_audit_files fd_out since =
+let transfer_all_audit_files fd_out ?filter since =
        let atransfer _infix _suffix =
                let infix = if _infix="" then "" else "."^_infix in
                let suffix = if _suffix="" then "" else "."^_suffix in
@@ -87,6 +98,7 @@
                        (audit_log_whitelist_prefix^infix^suffix)
                        _suffix
                        fd_out
+                       ?filter
                        since
        in
        let atransfer_try_gz infix =
diff -r f8298e1caacd -r 69e3ee3fb691 ocaml/xapi/xapi_vm_clone.ml
--- a/ocaml/xapi/xapi_vm_clone.ml
+++ b/ocaml/xapi/xapi_vm_clone.ml
@@ -254,7 +254,7 @@
       (let session = Context.get_session_id __context in
        let uname = Db.Session.get_auth_user_name ~__context ~self:session in
        let is_lsu = Db.Session.get_is_local_superuser ~__context ~self:session 
in
-       is_lsu && (uname = "__dom0__vmpr")
+       is_lsu && (uname = Xapi_vmpp.vmpr_username)
       )
                with e ->
       debug "Error obtaining is_snapshot_from_vmpp: %s" (Printexc.to_string e);
diff -r f8298e1caacd -r 69e3ee3fb691 ocaml/xapi/xapi_vmpp.ml
--- a/ocaml/xapi/xapi_vmpp.ml
+++ b/ocaml/xapi/xapi_vmpp.ml
@@ -15,6 +15,7 @@
 open D
 
 let vmpr_plugin = "vmpr"
+let vmpr_username = "__dom0__vmpr"
 
 let protect_now ~__context ~vmpp = 
   let vmpp_uuid = Db.VMPP.get_uuid ~__context ~self:vmpp in
@@ -34,6 +35,69 @@
     "archive_now"
     args
 
+let add_alert ~__context ~vmpp ~name ~priority ~body =
+  ()
+
+let get_alerts ~__context ~vmpp ~since =
+  let vmpp_uuid = Db.VMPP.get_uuid ~__context ~self:vmpp in
+  let filter=["unix-RPC|message.create";vmpr_username;vmpp_uuid] in
+  let tmp_filename = Filename.temp_file "vmpp-alerts-" ".dat" in
+  let fd = Unix.openfile tmp_filename [Unix.O_RDWR] 0o600 in
+  let since = Date.to_string since in
+  let messages=Audit_log.transfer_all_audit_files fd ~filter since in
+  let cout = Unix.out_channel_of_descr fd in
+  flush cout;
+  let cin = Unix.in_channel_of_descr fd in
+  seek_in cin 0;
+  let lines = ref [] in
+  let i = ref 0 in (* hard limit on maximum number of lines to parse *)
+  (try while !i<1000 do let line = input_line cin in lines:=line::!lines; 
i:=!i+1 done with End_of_file->());
+       let lines = !lines in
+  Unix.close fd;
+  Sys.remove tmp_filename;
+  let alerts = List.map (fun line->
+    let sexpr_init = try (String.index line ']')+1 with Not_found -> -1 in
+    if sexpr_init>=0 && sexpr_init<(String.length line) then (
+                       let sexpr_str = Stringext.String.sub_to_end line 
sexpr_init in
+                       let (sroot:SExpr.t) = 
+        (try SExpr_TS.of_string sexpr_str
+        with e->
+          debug "error %s parsing sexpr: %s"
+            (ExnHelper.string_of_exn e) sexpr_str
+          ;
+          (SExpr.Node [])
+        )
+      in
+      match sroot with
+                       |SExpr.Node (SExpr.String _::SExpr.String 
_::SExpr.String _::SExpr.String _::SExpr.String _::SExpr.String _::SExpr.String 
_::SExpr.Node params::[])->(
+        let kvs = List.fold_right (fun (sexpr:SExpr.t) acc ->
+        match sexpr with
+                                 |SExpr.Node (SExpr.String name::SExpr.String 
value::SExpr.String _::SExpr.String _::[]) when name="name" or name="body"->
+            (name,value)::acc
+          |_->acc
+        ) params []
+        in
+        if kvs=[] then None else Some kvs
+                       )
+                       |_->None
+               )
+    else None
+       ) lines
+  in
+  let alerts = List.fold_right (fun a acc->match a with None->acc|Some 
a->a::acc) alerts [] in
+  let inside_data_tag str =
+    let tag_begin="<data>" and tag_end="</data>" in
+    let tag_begin_idx=try List.hd (Stringext.String.find_all tag_begin str) 
with _-> -1 in
+    let tag_end_idx=try List.hd (List.rev (Stringext.String.find_all tag_end 
str)) with _-> -1 in
+    try
+      let start=(tag_begin_idx+(String.length tag_begin)) in
+      let len=tag_end_idx - start in
+      Some (String.sub str start len)
+    with _->None
+  in
+  let alerts = List.fold_right (fun a acc->if List.mem_assoc "body" a then 
(let data=inside_data_tag(List.assoc "body" a) in match data with 
None->acc|Some data->data::acc) else acc) alerts [] in
+  alerts
+
 let set_is_backup_running ~__context ~self ~value =
   Db.VMPP.set_is_backup_running ~__context ~self ~value
 
diff -r f8298e1caacd -r 69e3ee3fb691 scripts/mail-alarm
--- a/scripts/mail-alarm
+++ b/scripts/mail-alarm
@@ -17,6 +17,7 @@
 import traceback
 import syslog
 from xml.dom import minidom
+from xml.sax.saxutils import unescape
 from xml.parsers.expat import ExpatError
 from socket import getfqdn
 
@@ -286,6 +287,29 @@
             'This alarm is set to be triggered when a host belonging to a high 
availability pool fails.' \
             '\n' % self.text
 
+class VmppETG(EmailTextGenerator):
+    def __init__(self, msg):
+        self.msg = msg
+
+    def generate_subject(self):
+        msg = self.msg
+        return "[%s] XenServer Message: %s %s %s" % (msg.pool_name, msg.cls, 
msg.obj_uuid, msg.name)
+
+    def generate_body(self):
+        msg = self.msg
+        msg_body = unescape(msg.body)
+        try:
+            xmldoc = minidom.parseString(msg_body)
+            body_message = xmldoc.getElementsByTagName('message')[0]
+            email_message = 
body_message.getElementsByTagName('email')[0].firstChild.data
+            return \
+            
"Field\t\tValue\n-----\t\t-----\nName:\t\t%s\nPriority:\t%s\nClass:\t\t%s\n" \
+            "Object UUID:\t%s\nTimestamp:\t%s\nMessage UUID:\t%s\nPool 
name:\t%s\nBody:\t\t%s\n" % \
+            
(msg.name,msg.priority,msg.cls,msg.obj_uuid,msg.timestamp,msg.uuid,msg.pool_name,email_message)
+        except:
+            log_err("Badly formatted XML, or missing field")
+            sys.exit(1)
+
 class XapiMessage:
     def __init__(self, xml):
         "Parse message XML"
@@ -322,7 +346,9 @@
         if hasattr(self,'cached_etg'):
             return self.cached_etg
 
-        if self.name == 'ALARM':
+        if self.cls == 'VMPP':
+            etg = VmppETG(self)
+        elif self.name == 'ALARM':
             # Extract the current level of the variable
             # (this will raise an exception if the 1st line of <body> is not 
in the correct format, namely "value: %f\n")
             value_line = self.body.split("\n",2)[0]

Attachment: xen-api.hg-13.patch
Description: Text Data

_______________________________________________
xen-api mailing list
xen-api@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/mailman/listinfo/xen-api

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.