Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
itminedu
snf-ganeti
Commits
a0638838
Commit
a0638838
authored
Jul 24, 2008
by
Oleksiy Mishchenko
Browse files
Switch RAPI to ganeti.http module
Reviewed-by: imsnah
parent
0ad64cf8
Changes
6
Hide whitespace changes
Inline
Side-by-side
Makefile.am
View file @
a0638838
...
...
@@ -195,6 +195,7 @@ dist_TESTS = \
test
/ganeti.serializer_unittest.py
\
test
/ganeti.workerpool_unittest.py
\
test
/ganeti.rapi.resources_unittest.py
\
test
/ganeti.http_unittest.py
\
test
/ganeti.constants_unittest.py
nodist_TESTS
=
...
...
lib/http.py
View file @
a0638838
...
...
@@ -108,6 +108,7 @@ class ApacheLogfile:
# Message
format
%
args
,
))
self
.
_fd
.
flush
()
def
_FormatCurrentTime
(
self
):
"""Formats current time in Common Log Format.
...
...
lib/rapi/RESTHTTPServer.py
View file @
a0638838
...
...
@@ -20,217 +20,56 @@
"""
import
BaseHTTPServer
import
OpenSSL
import
re
import
socket
import
time
from
ganeti
import
constants
from
ganeti
import
http
from
ganeti
import
errors
from
ganeti
import
logger
from
ganeti
import
rpc
from
ganeti
import
serializer
from
ganeti.rapi
import
connector
from
ganeti.rapi
import
httperror
class
HttpLogfile
:
"""Utility class to write HTTP server log files.
The written format is the "Common Log Format" as defined by Apache:
http://httpd.apache.org/docs/2.2/mod/mod_log_config.html#examples
"""
MONTHNAME
=
[
None
,
'Jan'
,
'Feb'
,
'Mar'
,
'Apr'
,
'May'
,
'Jun'
,
'Jul'
,
'Aug'
,
'Sep'
,
'Oct'
,
'Nov'
,
'Dec'
]
def
__init__
(
self
,
path
):
self
.
_fd
=
open
(
path
,
'a'
,
1
)
def
__del__
(
self
):
try
:
self
.
Close
()
except
:
# Swallow exceptions
pass
def
Close
(
self
):
if
self
.
_fd
is
not
None
:
self
.
_fd
.
close
()
self
.
_fd
=
None
def
LogRequest
(
self
,
request
,
format
,
*
args
):
if
self
.
_fd
is
None
:
raise
errors
.
ProgrammerError
(
"Logfile already closed"
)
request_time
=
self
.
_FormatCurrentTime
()
self
.
_fd
.
write
(
"%s %s %s [%s] %s
\n
"
%
(
# Remote host address
request
.
address_string
(),
# RFC1413 identity (identd)
"-"
,
# Remote user
"-"
,
# Request time
request_time
,
# Message
format
%
args
,
))
def
_FormatCurrentTime
(
self
):
"""Formats current time in Common Log Format.
"""
return
self
.
_FormatLogTime
(
time
.
time
())
def
_FormatLogTime
(
self
,
seconds
):
"""Formats time for Common Log Format.
All timestamps are logged in the UTC timezone.
Args:
- seconds: Time in seconds since the epoch
"""
(
_
,
month
,
_
,
_
,
_
,
_
,
_
,
_
,
_
)
=
tm
=
time
.
gmtime
(
seconds
)
format
=
"%d/"
+
self
.
MONTHNAME
[
month
]
+
"/%Y:%H:%M:%S +0000"
return
time
.
strftime
(
format
,
tm
)
class
RESTHTTPServer
(
BaseHTTPServer
.
HTTPServer
):
"""Class to provide an HTTP/HTTPS server.
"""
allow_reuse_address
=
True
def
__init__
(
self
,
server_address
,
HandlerClass
,
options
):
"""REST Server Constructor.
Args:
server_address: a touple containing:
ip: a string with IP address, localhost if empty string
port: port number, integer
HandlerClass: HTTPRequestHandler object
options: Command-line options
"""
logger
.
SetupLogging
(
debug
=
options
.
debug
,
program
=
'ganeti-rapi'
)
self
.
httplog
=
HttpLogfile
(
constants
.
LOG_RAPIACCESS
)
BaseHTTPServer
.
HTTPServer
.
__init__
(
self
,
server_address
,
HandlerClass
)
if
options
.
ssl
:
# Set up SSL
context
=
OpenSSL
.
SSL
.
Context
(
OpenSSL
.
SSL
.
SSLv23_METHOD
)
context
.
use_privatekey_file
(
options
.
ssl_key
)
context
.
use_certificate_file
(
options
.
ssl_cert
)
self
.
socket
=
OpenSSL
.
SSL
.
Connection
(
context
,
socket
.
socket
(
self
.
address_family
,
self
.
socket_type
))
else
:
self
.
socket
=
socket
.
socket
(
self
.
address_family
,
self
.
socket_type
)
self
.
server_bind
()
self
.
server_activate
()
class
JsonResponse
:
CONTENT_TYPE
=
"application/json"
def
Encode
(
self
,
data
):
return
serializer
.
DumpJson
(
data
)
class
RESTRequestHandler
(
BaseHTTPServer
.
BaseHTTPRequestHandler
):
class
RESTRequestHandler
(
http
.
HTTPRequestHandler
):
"""REST Request Handler Class.
"""
def
setup
(
self
):
"""Setup secure read and write file objects.
"""
self
.
connection
=
self
.
request
self
.
rfile
=
socket
.
_fileobject
(
self
.
request
,
"rb"
,
self
.
rbufsize
)
self
.
wfile
=
socket
.
_fileobject
(
self
.
request
,
"wb"
,
self
.
wbufsize
)
super
(
RESTRequestHandler
,
self
).
setup
()
self
.
_resmap
=
connector
.
Mapper
()
def
h
andle
_one_r
equest
(
self
):
"""Hand
le a single REST
request.
def
H
andle
R
equest
(
self
):
"""
Hand
els a
request.
"""
self
.
raw_requestline
=
None
try
:
self
.
raw_requestline
=
self
.
rfile
.
readline
()
except
OpenSSL
.
SSL
.
Error
,
ex
:
logger
.
Error
(
"Error in SSL: %s"
%
str
(
ex
))
if
not
self
.
raw_requestline
:
self
.
close_connection
=
1
return
if
not
self
.
parse_request
():
# An error code has been sent, just exit
return
(
HandlerClass
,
items
,
args
)
=
self
.
_resmap
.
getController
(
self
.
path
)
handler
=
HandlerClass
(
self
,
items
,
args
)
command
=
self
.
command
.
upper
()
try
:
(
HandlerClass
,
items
,
args
)
=
self
.
_resmap
.
getController
(
self
.
path
)
handler
=
HandlerClass
(
self
,
items
,
args
)
fn
=
getattr
(
handler
,
command
)
except
AttributeError
,
err
:
raise
httperror
.
HTTPBadRequest
()
command
=
self
.
command
.
upper
()
try
:
fn
=
getattr
(
handler
,
command
)
except
AttributeError
,
err
:
raise
httperror
.
HTTPBadRequest
()
try
:
result
=
fn
()
except
errors
.
OpPrereqError
,
err
:
# TODO: "Not found" is not always the correct error. Ganeti's core must
# differentiate between different error types.
raise
httperror
.
HTTPNotFound
(
message
=
str
(
err
))
encoder
=
JsonResponse
()
encoded_result
=
encoder
.
Encode
(
result
)
self
.
send_response
(
200
)
self
.
send_header
(
"Content-Type"
,
encoder
.
CONTENT_TYPE
)
self
.
end_headers
()
self
.
wfile
.
write
(
encoded_result
)
except
httperror
.
HTTPException
,
err
:
self
.
send_error
(
err
.
code
,
message
=
err
.
message
)
except
Exception
,
err
:
self
.
send_error
(
httperror
.
HTTPInternalError
.
code
,
message
=
str
(
err
))
def
log_message
(
self
,
format
,
*
args
):
"""Log an arbitrary message.
This is used by all other logging functions.
The first argument, FORMAT, is a format string for the
message to be logged. If the format string contains
any % escapes requiring parameters, they should be
specified as subsequent arguments (it's just like
printf!).
try
:
result
=
fn
()
"""
self
.
server
.
httplog
.
LogRequest
(
self
,
format
,
*
args
)
except
errors
.
OpPrereqError
,
err
:
# TODO: "Not found" is not always the correct error. Ganeti's core must
# differentiate between different error types.
raise
httperror
.
HTTPNotFound
(
message
=
str
(
err
))
return
result
def
start
(
options
):
# Disable signal handlers, otherwise we can't exit the daemon in a clean way
# by sending a signal.
rpc
.
install_twisted_signal_handlers
=
False
httpd
=
RESTHTTPServer
((
""
,
options
.
port
),
RESTRequestHandler
,
options
)
log_fd
=
open
(
constants
.
LOG_RAPIACCESS
,
'a'
)
try
:
httpd
.
serve_forever
()
apache_log
=
http
.
ApacheLogfile
(
log_fd
)
httpd
=
http
.
HTTPServer
((
""
,
options
.
port
),
RESTRequestHandler
,
httplog
=
apache_log
)
try
:
httpd
.
serve_forever
()
finally
:
httpd
.
server_close
()
finally
:
httpd
.
server_
close
()
log_fd
.
close
()
lib/rapi/connector.py
View file @
a0638838
...
...
@@ -26,9 +26,9 @@ import cgi
import
re
from
ganeti
import
constants
from
ganeti
import
http
from
ganeti.rapi
import
baserlib
from
ganeti.rapi
import
httperror
from
ganeti.rapi
import
rlib1
from
ganeti.rapi
import
rlib2
...
...
@@ -85,10 +85,10 @@ class Mapper:
result
=
(
handler
,
[],
args
)
break
if
result
is
not
None
:
if
result
:
return
result
else
:
raise
http
error
.
HTTPNotFound
()
raise
http
.
HTTPNotFound
()
class
R_root
(
baserlib
.
R_Generic
):
...
...
test/ganeti.http_unittest.py
0 → 100755
View file @
a0638838
#!/usr/bin/python
#
# Copyright (C) 2007, 2008 Google 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.
"""Script for unittesting the http module"""
import
os
import
unittest
import
tempfile
import
time
from
ganeti
import
http
class
HttpLogfileTests
(
unittest
.
TestCase
):
"""Rests for ApacheLogfile class."""
class
FakeRequest
:
FAKE_ADDRESS
=
"1.2.3.4"
def
address_string
(
self
):
return
self
.
FAKE_ADDRESS
def
setUp
(
self
):
self
.
tmpfile
=
tempfile
.
NamedTemporaryFile
()
self
.
logfile
=
http
.
ApacheLogfile
(
self
.
tmpfile
)
def
tearDown
(
self
):
self
.
tmpfile
.
close
()
def
testFormatLogTime
(
self
):
self
.
_TestInTimezone
(
1208646123.0
,
"Europe/London"
,
"19/Apr/2008:23:02:03 +0000"
)
self
.
_TestInTimezone
(
1208646123
,
"Europe/Zurich"
,
"19/Apr/2008:23:02:03 +0000"
)
self
.
_TestInTimezone
(
1208646123
,
"Australia/Sydney"
,
"19/Apr/2008:23:02:03 +0000"
)
def
_TestInTimezone
(
self
,
seconds
,
timezone
,
expected
):
"""Tests HttpLogfile._FormatLogTime with a specific timezone
"""
# Preserve environment
old_TZ
=
os
.
environ
.
get
(
"TZ"
,
None
)
try
:
os
.
environ
[
"TZ"
]
=
timezone
time
.
tzset
()
result
=
self
.
logfile
.
_FormatLogTime
(
seconds
)
finally
:
# Restore environment
if
old_TZ
is
not
None
:
os
.
environ
[
"TZ"
]
=
old_TZ
elif
"TZ"
in
os
.
environ
:
del
os
.
environ
[
"TZ"
]
time
.
tzset
()
self
.
assertEqual
(
result
,
expected
)
def
testLogRequest
(
self
):
request
=
self
.
FakeRequest
()
self
.
logfile
.
LogRequest
(
request
,
"This is only a %s"
,
"test"
)
if
__name__
==
'__main__'
:
unittest
.
main
()
test/ganeti.rapi.resources_unittest.py
View file @
a0638838
...
...
@@ -22,14 +22,13 @@
"""Script for unittesting the RAPI resources module"""
import
os
import
unittest
import
tempfile
import
time
from
ganeti
import
errors
from
ganeti
import
http
from
ganeti.rapi
import
connector
from
ganeti.rapi
import
httperror
from
ganeti.rapi
import
RESTHTTPServer
from
ganeti.rapi
import
rlib1
...
...
@@ -44,7 +43,7 @@ class MapperTests(unittest.TestCase):
self
.
assertEquals
(
self
.
map
.
getController
(
uri
),
result
)
def
_TestFailingUri
(
self
,
uri
):
self
.
failUnlessRaises
(
http
error
.
HTTPNotFound
,
self
.
map
.
getController
,
uri
)
self
.
failUnlessRaises
(
http
.
HTTPNotFound
,
self
.
map
.
getController
,
uri
)
def
testMapper
(
self
):
"""Testing Mapper"""
...
...
@@ -86,61 +85,5 @@ class R_RootTests(unittest.TestCase):
self
.
assertEquals
(
self
.
root
.
GET
(),
expected
)
class
HttpLogfileTests
(
unittest
.
TestCase
):
"""Rests for HttpLogfile class."""
class
FakeRequest
:
FAKE_ADDRESS
=
"1.2.3.4"
def
address_string
(
self
):
return
self
.
FAKE_ADDRESS
def
setUp
(
self
):
self
.
tmpfile
=
tempfile
.
NamedTemporaryFile
()
self
.
logfile
=
RESTHTTPServer
.
HttpLogfile
(
self
.
tmpfile
.
name
)
def
testFormatLogTime
(
self
):
self
.
_TestInTimezone
(
1208646123.0
,
"Europe/London"
,
"19/Apr/2008:23:02:03 +0000"
)
self
.
_TestInTimezone
(
1208646123
,
"Europe/Zurich"
,
"19/Apr/2008:23:02:03 +0000"
)
self
.
_TestInTimezone
(
1208646123
,
"Australia/Sydney"
,
"19/Apr/2008:23:02:03 +0000"
)
def
_TestInTimezone
(
self
,
seconds
,
timezone
,
expected
):
"""Tests HttpLogfile._FormatLogTime with a specific timezone
"""
# Preserve environment
old_TZ
=
os
.
environ
.
get
(
"TZ"
,
None
)
try
:
os
.
environ
[
"TZ"
]
=
timezone
time
.
tzset
()
result
=
self
.
logfile
.
_FormatLogTime
(
seconds
)
finally
:
# Restore environment
if
old_TZ
is
not
None
:
os
.
environ
[
"TZ"
]
=
old_TZ
elif
"TZ"
in
os
.
environ
:
del
os
.
environ
[
"TZ"
]
time
.
tzset
()
self
.
assertEqual
(
result
,
expected
)
def
testClose
(
self
):
self
.
logfile
.
Close
()
def
testCloseAndWrite
(
self
):
request
=
self
.
FakeRequest
()
self
.
logfile
.
Close
()
self
.
assertRaises
(
errors
.
ProgrammerError
,
self
.
logfile
.
LogRequest
,
request
,
"Message"
)
def
testLogRequest
(
self
):
request
=
self
.
FakeRequest
()
self
.
logfile
.
LogRequest
(
request
,
"This is only a %s"
,
"test"
)
self
.
logfile
.
Close
()
if
__name__
==
'__main__'
:
unittest
.
main
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment