libvirt_rpc/
lib.rs

1extern crate xdr_codec;
2extern crate byteorder;
3extern crate uuid;
4extern crate tokio_io;
5extern crate tokio_proto;
6extern crate tokio_service;
7extern crate tokio_core;
8extern crate tokio_uds;
9extern crate tokio_uds_proto;
10extern crate bytes;
11#[macro_use]
12extern crate futures;
13#[macro_use]
14extern crate log;
15extern crate env_logger;
16#[macro_use]
17extern crate bitflags;
18
19use xdr_codec::{Unpack};
20
21use byteorder::NetworkEndian;
22
23pub mod request;
24pub mod async;
25mod proto;
26use request::*;
27
28use std::io::Cursor;
29
30pub struct Libvirt<Io: ::std::io::Read+::std::io::Write> {
31    serial: u32,
32    stream: Io,
33}
34
35/// Represents error 
36#[derive(Debug)]
37pub enum LibvirtError {
38    /// IO error
39    IoError(::std::io::Error),
40    /// Error during serialization / deserialization
41    XdrError(xdr_codec::Error),
42    /// Libvirtd returned error
43    Libvirt(request::virNetMessageError),
44}
45
46impl LibvirtError {
47    pub fn is_io(&self) -> bool {
48        if let &LibvirtError::IoError(_) = self {
49            true
50        } else {
51            false
52        }
53    }
54}
55
56impl ::std::convert::From<::std::io::Error> for LibvirtError {
57    fn from(e: ::std::io::Error) -> Self {
58        LibvirtError::IoError(e.into())
59    }
60}
61
62impl ::std::convert::From<xdr_codec::Error> for LibvirtError {
63    fn from(e: xdr_codec::Error) -> Self {
64        LibvirtError::XdrError(e)
65    }
66}
67
68impl ::std::convert::From<virNetMessageError> for LibvirtError {
69    fn from(e: virNetMessageError) -> Self {
70        LibvirtError::Libvirt(e)
71    }
72}
73
74impl ::std::fmt::Display for LibvirtError {
75    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
76        match self {
77           &LibvirtError::XdrError(ref e) => e.fmt(f),
78           &LibvirtError::IoError(ref e) => e.fmt(f),
79           &LibvirtError::Libvirt(ref vmsg) => vmsg.fmt(f),
80        }
81    }
82}
83
84impl ::std::error::Error for LibvirtError {
85    fn description(&self) -> &str {
86        match self {
87            &LibvirtError::XdrError(ref e) => e.description(),
88            &LibvirtError::IoError(ref e) => e.description(),
89            &LibvirtError::Libvirt(ref vmsg) => vmsg.description(),
90        }
91    }
92
93}
94
95impl ::std::fmt::Display for virNetMessageError {
96    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
97        match self.message {
98            Some(ref msg) => write!(f, "{}", &msg.0),
99            None => write!(f, "{:?}", self.message),
100        }
101    }
102}
103
104impl ::std::error::Error for virNetMessageError {
105    fn description(&self) -> &str {
106        match self.message {
107            Some(ref msg) => &msg.0,
108            None => panic!("virNetMessageError message absent"),
109        }
110    }
111}
112
113impl<Io> Libvirt<Io> where Io: ::std::io::Read+::std::io::Write {
114    pub fn new(stream: Io) -> Self {
115        Libvirt {
116            serial: 0,
117            stream: stream,
118        }
119    }
120
121    fn serial(&mut self) -> u32 {
122        let serial = self.serial;
123        self.serial += 1;
124        return serial;
125    }
126
127    fn write_packet<P: xdr_codec::Pack<Cursor<Vec<u8>>>>(&mut self, packet: P) -> xdr_codec::Result<usize> {
128        use std::io::Cursor;
129        use byteorder::WriteBytesExt;
130
131        let buf = Vec::new();
132        let (sz, buf) = {
133            let mut c = Cursor::new(buf);
134            let sz = try!(packet.pack(&mut c));
135            let inner = c.into_inner();
136            (sz, inner)
137        };
138        let len = sz + 4;
139        try!(self.stream.write_u32::<NetworkEndian>(len as u32));
140        try!(self.stream.write(&buf[0..sz]));
141        //println!("LEN = {:?}\n", len);
142        Ok(len as usize)
143    }
144
145    /*
146    fn read_packet_raw(&mut self) -> Result<Vec<u8>, LibvirtError> {
147        use byteorder::ReadBytesExt;
148
149        let mut len = try!(self.stream.read_u32::<NetworkEndian>());
150        //println!("TOTAL LENGTH {}", len);
151        len -= 4; // skip len
152
153        let mut buf = vec![0;len as usize];
154        try!(self.stream.read_exact(&mut buf[0..len as usize]));
155        let mut cur = Cursor::new(buf);
156
157        let (header, hlen) = try!(virNetMessageHeader::unpack(&mut cur));
158       
159        if header.status == virNetMessageStatus::VIR_NET_OK {
160            let buf = cur.into_inner();
161            return Ok(buf);
162        }
163
164        let (err, _) = try!(virNetMessageError::unpack(&mut cur));
165        return Err(LibvirtError::from(err));
166    }
167    */
168
169    fn read_packet_reply<P: xdr_codec::Unpack<Cursor<Vec<u8>>>>(&mut self) -> Result<P, LibvirtError> {
170        use byteorder::{ReadBytesExt};
171
172        let mut len = try!(self.stream.read_u32::<NetworkEndian>());
173        len -= 4; // skip len
174
175        // read whole packet
176        let mut buf = vec![0;len as usize];
177        try!(self.stream.read_exact(&mut buf[0..len as usize]));
178        let mut cur = Cursor::new(buf);
179
180        let (header, _) = try!(virNetMessageHeader::unpack(&mut cur));
181       
182        if header.status == virNetMessageStatus::VIR_NET_OK {
183            let (pkt, _) = try!(P::unpack(&mut cur));
184            return Ok(pkt);
185        }
186
187        let (err, _) = try!(virNetMessageError::unpack(&mut cur));
188        return Err(LibvirtError::from(err));
189    }
190
191    fn request<Req: xdr_codec::Pack<Cursor<Vec<u8>>>, Resp: xdr_codec::Unpack<Cursor<Vec<u8>>>>(&mut self, packet: Req) -> Result<Resp, LibvirtError> {
192        try!(self.write_packet(packet));
193        self.read_packet_reply()
194    }
195
196    fn make_request<T>(&mut self, procedure: request::remote_procedure, payload: T) -> request::LibvirtMessage<T> {
197        use std::default::Default;
198        let serial = self.serial();
199
200        LibvirtMessage {
201            header: request::virNetMessageHeader {
202                serial: serial,
203                proc_: procedure as i32,
204                ..Default::default()
205            },
206            payload: payload,
207        }
208    }
209
210    pub fn auth(&mut self) -> Result<AuthListResponse, LibvirtError> {
211        use request::remote_procedure::*;
212        let req = self.make_request(REMOTE_PROC_AUTH_LIST, AuthListRequest::new());
213        self.request(req)
214    }
215
216    pub fn open(&mut self) -> Result<ConnectOpenResponse, LibvirtError> {
217        use request::remote_procedure::*;
218        let req = self.make_request(REMOTE_PROC_CONNECT_OPEN, ConnectOpenRequest::new());
219        self.request(req)
220    }
221
222    pub fn version(&mut self) -> Result<(u32, u32, u32), LibvirtError> {
223        use request::remote_procedure::*;
224        let req = self.make_request(REMOTE_PROC_CONNECT_GET_LIB_VERSION, GetLibVersionRequest::new());
225
226        let pkt: GetLibVersionResponse = try!(self.request(req));
227
228        Ok(pkt.version())
229    }
230
231    pub fn list_defined_domains(&mut self) -> Result<Vec<String>, LibvirtError> {
232        use request::remote_procedure::*;
233        let req = self.make_request(REMOTE_PROC_CONNECT_LIST_DEFINED_DOMAINS, ListDefinedDomainsRequest::new());
234
235        let pkt: ListDefinedDomainsResponse = try!(self.request(req));
236        let names = pkt.get_domain_names();
237        Ok(names)
238    }
239
240    pub fn define(&mut self, xml: &str) -> Result<Domain, LibvirtError> {
241        use request::remote_procedure::*;
242        let req = self.make_request(REMOTE_PROC_DOMAIN_DEFINE_XML_FLAGS, DomainDefineXMLRequest::new(xml, 1));
243
244        let pkt: DomainDefineXMLResponse = try!(self.request(req));
245        let dom = pkt.get_domain();
246        Ok(dom)
247    }
248
249    pub fn undefine(&mut self, dom: Domain) -> Result<DomainUndefineResponse, LibvirtError> {
250        use request::remote_procedure::*;
251        let req = self.make_request(REMOTE_PROC_DOMAIN_UNDEFINE_FLAGS, DomainUndefineRequest::new(dom, 0));
252
253        self.request(req)
254    }
255
256    pub fn start(&mut self, dom: Domain) -> Result<Domain, LibvirtError> {
257        use request::remote_procedure::*;
258        let req = self.make_request(REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS, DomainCreateRequest::new(dom, DomainCreateFlags::DomainCreateFlags::empty()));
259
260        let pkt: DomainCreateResponse = try!(self.request(req));
261        let dom = pkt.get_domain();
262        Ok(dom)
263    }
264}
265#[cfg(test)]
266mod tests {
267    /*
268    #[test]
269    fn no_it_doesnt() {
270        use std::fs::File;
271        use super::Libvirt;
272        use std::os::unix::net::UnixStream;
273        use std::io::Read;
274        let mut stream = UnixStream::connect("/var/run/libvirt/libvirt-sock").unwrap();
275        let mut libvirt = Libvirt::new(stream);
276        println!("authorizing");
277        libvirt.auth().unwrap();
278        println!("opening");
279        libvirt.open().unwrap();
280        println!("getting version");
281        let (major, minor, micro) = libvirt.version().unwrap();
282        println!("version: {}.{}.{}", major, minor, micro);
283        let names = libvirt.list_defined_domains();
284        println!("domains: {:?}", names);
285        let mut f = File::open("test.xml").unwrap();
286        let mut xml = String::new();
287        f.read_to_string(&mut xml).unwrap();
288        let dom = libvirt.define(&xml).unwrap();
289        println!("new domain: name: {:?} uuid: {:?}", dom.name(), dom.uuid());
290        let names = libvirt.list_defined_domains();
291        println!("domains: {:?}", names);
292        let dom = libvirt.start(dom).unwrap();
293        //libvirt.undefine(dom).unwrap();
294        let names = libvirt.list_defined_domains();
295        println!("domains: {:?}", names);
296    }
297    */
298    /*
299    #[test]
300    fn it_works() {
301        use std::os::unix::net::UnixStream;
302        let mut stream = UnixStream::connect("/var/run/libvirt/libvirt-sock").unwrap();
303        use super::{auth,version};
304        auth(&mut stream);
305        version(&mut stream);
306    }
307    */
308}