source: vanHelsing/trunk/bconsole.py@ 772

Last change on this file since 772 was 772, checked in by hmueller, on Jul 1, 2009 at 5:15:41 PM
  • Property svn:executable set to *
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-python
File size: 5.4 KB
Line 
1#!/usr/bin/env python
2# simple illustration client/server pair; client program sends a string
3# to server, which echoes it back to the client (in multiple copies),
4# and the latter prints to the screen
5# this is the client
6import socket
7import sys
8import struct
9import re
10import time
11import md5
12
13PORT = 9101
14BUFSIZE = 1048576
15
16# BNET signals
17BNET_SIGNALS = {
18 'BNET_EOD' : -1, # End of data stream, new data may follow
19 'BNET_EOD_POLL' : -2, # End of data and poll all in one
20 'BNET_STATUS' : -3, # Send full status
21 'BNET_TERMINATE' : -4, # Conversation terminated, doing close()
22 'BNET_POLL' : -5, # Poll request, I'm hanging on a read
23 'BNET_HEARTBEAT' : -6, # Heartbeat Response requested
24 'BNET_HB_RESPONSE' : -7, # Only response permited to HB
25 'BNET_PROMPT' : -8, # Prompt for subcommand
26 'BNET_BTIME' : -9, # Send UTC btime
27 'BNET_BREAK' : -10, # Stop current command -- ctl-c
28 'BNET_START_SELECT' : -11, # Start of a selection list
29 'BNET_END_SELECT' : -12, # End of a select list
30 'BNET_INVALID_CMD' : -13, # Invalid command sent
31 'BNET_CMD_FAILED' : -14, # Command failed
32 'BNET_CMD_OK' : -15, # Command succeeded
33 'BNET_CMD_BEGIN' : -16, # Start command execution
34 'BNET_MSGS_PENDING' : -17, # Messages pending
35 'BNET_MAIN_PROMPT' : -18, # Server ready and waiting
36 'BNET_SELECT_INPUT' : -19, # Return selection input
37 'BNET_WARNING_MSG' : -20, # Warning message
38 'BNET_ERROR_MSG' : -21, # Error message -- command failed
39 'BNET_INFO_MSG' : -22, # Info message -- status line
40 'BNET_RUN_CMD' : -23, # Run command follows
41 'BNET_YESNO' : -24, # Request yes no response
42 'BNET_START_RTREE' : -25, # Start restore tree mode
43 'BNET_END_RTREE' : -26, # End restore tree mode
44}
45
46#import clibbac
47
48class ConsoleError(IOError):
49 pass
50
51class Console:
52 """Class to connect with the bacula director as a console client
53 """
54
55 HELLO = r"Hello %s calling"
56 HELLO_OK = "1000 OK"
57 RXP_RESP = re.compile(
58 """^auth\scram-md5(?P<compatible>c?)\s
59 (?P<challenge>\S+)\s
60 ssl=(?P<tls>\d)""",
61 re.VERBOSE)
62
63 def __init__(self, host="bacula", port=PORT):
64 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
65 self.socket.connect((host, port))
66 self.last_state = 0
67
68 def __del__(self):
69 """Destructor closes the network socket"""
70 self.socket.close()
71
72 def _send(self, data):
73 """Prepend size of data before the data string
74 and send it trough the socket"""
75 size = struct.pack("!i", len(data))
76 self.socket.send(size + data)
77
78 def _recv(self, bufsize=BUFSIZE):
79 """Recieve data from socket and strip the prepended
80 data size"""
81 r = self.socket.recv(4)
82 size = struct.unpack("!i", r)[0]
83 if size < 0:
84 self.last_state = size
85 r = ""
86 elif size + 4 > BUFSIZE:
87 raise ConsoleError("Buffer to small: %i" %size)
88 else:
89 r = self.socket.recv(size)
90 return r
91
92 def _recv_all(self):
93 """Gets all lines of a request"""
94 r = ""
95 s = self._recv()
96 while s:
97 r += s
98 s = self._recv()
99 return r
100
101 def login(self, username, password):
102 pw = md5.md5(password).hexdigest()
103
104 self._send(self.HELLO % username + "\n")
105 response = self._recv()
106
107 # Challenge from director
108 m = self.RXP_RESP.search(response)
109 challenge = clibbac.hmac_md5(m.group("challenge"), pw)
110 self._send(clibbac.bin_to_base64(challenge[:16], False))
111 resp = self._recv()
112 if not resp.startswith(self.HELLO_OK):
113 raise ConsoleError("Challenge: %s" % resp)
114
115 # now from client site
116 now = time.time()
117 respond = clibbac.bin_to_base64(
118 clibbac.hmac_md5("<%10.10f@bconsole>" % now, pw)[:16],
119 False)
120 self._send("auth cram-md5 <%10.10f@bconsole> ssl=0\n" % now)
121 resp = self._recv().rstrip("\x000")
122 if resp != respond:
123 print len(resp)
124 print len(respond)
125 raise ConsoleError("Respond: %s expected: %s" % (resp, respond))
126 self._send("1000 OK auth\n")
127
128 return self._recv()
129
130 def version(self):
131 """Returns the bacula director version string"""
132 self._send("version")
133 return self._recv_all().split("\n")[0]
134
135 def dotstatus(self):
136 self._send(".status dir current")
137 return self._recv_all()
138
139if __name__ == "__main__":
140 try:
141 host = sys.argv[1]
142 port = int(sys.argv[2])
143 except:
144 host = "bacula-devel"
145 port = 9101
146
147 print sys.path
148
149 console = Console(host, port)
150 console.login("python", "dass-it")
151
152 print console.version()
153 print console.dotstatus()
154
155
156#....Hello python calling
157#...7auth cram-md5 <1938954300.1244114680@bacula-dir> ssl=0
158#....XRx1dCJU36/UJD/l7TBZZC....
159#1000 OK auth
160#...4auth cram-md5 <238682207.1244114679@bconsole> ssl=0
161#....klIi6CczoW89Bl/wCA04wA....
162#1000 OK auth
163#...31000 OK: bacula-dir Version: 3.0.1 (30 April 2009)
Note: See TracBrowser for help on using the repository browser.