Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
slapos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Vincent Bechu
slapos
Commits
728d2e39
Commit
728d2e39
authored
Nov 13, 2012
by
Marco Mariani
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: removed templating over python code, added logging
parent
c462fa96
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
328 additions
and
47 deletions
+328
-47
slapos/recipe/addresiliency/__init__.py
slapos/recipe/addresiliency/__init__.py
+41
-47
slapos/recipe/addresiliency/bully.py
slapos/recipe/addresiliency/bully.py
+287
-0
slapos/recipe/addresiliency/template/bully.conf.in
slapos/recipe/addresiliency/template/bully.conf.in
+0
-0
No files found.
slapos/recipe/addresiliency/__init__.py
View file @
728d2e39
...
...
@@ -26,7 +26,6 @@
##############################################################################
from
slapos.recipe.librecipe
import
GenericSlapRecipe
import
sys
import
os
...
...
@@ -37,46 +36,41 @@ class Recipe(GenericSlapRecipe):
def
_install
(
self
):
path_list
=
[]
self_id
=
int
(
self
.
parameter_dict
[
'number'
])
confpath
=
os
.
path
.
join
(
self
.
options
[
'script'
],
'bully.conf'
)
ip
=
self
.
parameter_dict
[
'ip-list'
].
split
(
' '
)
print
'Creating bully script with ips : %s
\
n
'
%
ip
slap_connection
=
self
.
buildout
[
'slap-connection'
]
print
'Creating bully configuration with ips : %s
\
n
'
%
ip
path_conf
=
os
.
path
.
join
(
self
.
options
[
'script'
],
'conf.in'
)
path_bully
=
os
.
path
.
join
(
self
.
options
[
'script'
],
self
.
parameter_dict
[
'script'
])
path_bully_new
=
os
.
path
.
join
(
self
.
options
[
'script'
],
'new.py'
)
# XXX use the bin directory, do not run automatically yet
path_run
=
os
.
path
.
join
(
self
.
options
[
'bin'
],
self
.
parameter_dict
[
'wrapper'
])
print
'paths: %s
\
n
%s
\
n
'
%
(
path_run
,
path_bully
)
bully_conf
=
dict
(
self_id
=
self_id
,
ip_list
=
ip
,
executable
=
sys
.
executable
,
syspath
=
sys
.
path
,
server_url
=
slap_connection
[
'server-url'
],
key_file
=
slap_connection
.
get
(
'key-file'
),
cert_file
=
slap_connection
.
get
(
'cert-file'
),
computer_id
=
slap_connection
[
'computer-id'
],
partition_id
=
slap_connection
[
'partition-id'
],
software
=
slap_connection
[
'software-release-url'
],
namebase
=
self
.
parameter_dict
[
'namebase'
],
confpath
=
path_conf
)
try
:
conf
=
self
.
createFile
(
path_conf
,
conf
=
self
.
createFile
(
confpath
,
self
.
substituteTemplate
(
self
.
getTemplateFilename
(
'conf.in.in'
),
bully_conf
))
self
.
getTemplateFilename
(
'bully.conf.in'
),
{
'self_id'
:
int
(
self
.
parameter_dict
[
'number'
]),
'ip_list'
:
ip
}
))
path_list
.
append
(
conf
)
script
=
self
.
createExecutable
(
path_bully
,
self
.
substituteTemplate
(
self
.
getTemplateFilename
(
'bully.py.in'
),
bully_conf
))
path_list
.
append
(
script
)
slap_connection
=
self
.
buildout
[
'slap-connection'
]
# XXX use the bin directory, do not run automatically yet
wrapper
=
self
.
createPythonScript
(
path_run
,
'slapos.recipe.librecipe.execute.execute'
,
[
path_bully
])
name
=
os
.
path
.
join
(
self
.
options
[
'bin'
],
self
.
parameter_dict
[
'wrapper'
]),
absolute_function
=
'slapos.recipe.addresiliency.bully.run'
,
arguments
=
{
'confpath'
:
confpath
,
'server_url'
:
slap_connection
[
'server-url'
],
'key_file'
:
slap_connection
.
get
(
'key-file'
),
'cert_file'
:
slap_connection
.
get
(
'cert-file'
),
'computer_id'
:
slap_connection
[
'computer-id'
],
'partition_id'
:
slap_connection
[
'partition-id'
],
'software'
:
slap_connection
[
'software-release-url'
],
'namebase'
:
self
.
parameter_dict
[
'namebase'
],
})
path_list
.
append
(
wrapper
)
except
IOError
:
pass
return
path_list
slapos/recipe/addresiliency/bully.py
0 → 100644
View file @
728d2e39
# -*- coding: utf-8 -*-
import
logging
import
socket
import
thread
import
time
from
slapos
import
slap
as
slapmodule
import
slapos
BASE_PORT
=
50000
SLEEPING_MINS
=
2
# XXX was 30, increase after testing
log
=
logging
.
getLogger
(
__name__
)
logging
.
basicConfig
(
level
=
logging
.
DEBUG
)
class
Renamer
(
object
):
def
__init__
(
self
,
server_url
,
key_file
,
cert_file
,
computer_guid
,
partition_id
,
software_release
,
namebase
):
self
.
server_url
=
server_url
self
.
key_file
=
key_file
self
.
cert_file
=
cert_file
self
.
computer_guid
=
computer_guid
self
.
partition_id
=
partition_id
self
.
software_release
=
software_release
self
.
namebase
=
namebase
def
_failover
(
self
):
slap
=
slapmodule
.
slap
()
slap
.
initializeConnection
(
self
.
server_url
,
self
.
key_file
,
self
.
cert_file
)
# partition that will take over
cp
=
slap
.
registerComputerPartition
(
computer_guid
=
self
.
computer_guid
,
partition_id
=
self
.
partition_id
)
cp_old_name
=
self
.
namebase
+
'0'
# partition to be deactivated
broken
=
cp
.
request
(
software_release
=
self
.
software_release
,
software_type
=
'frozen'
,
partition_reference
=
cp_old_name
)
broken_new_name
=
'broken-{}'
.
format
(
time
.
strftime
(
"%d-%b_%H:%M:%S"
,
time
.
gmtime
()))
# XXX how to print the old name
log
.
debug
(
"Renaming {}: {}"
.
format
(
broken
.
getId
(),
broken_new_name
))
broken
.
rename
(
broken_new_name
)
broken
.
stopped
()
log
.
debug
(
"Renaming {}: {}"
.
format
(
cp
.
getId
(),
cp_old_name
))
cp
.
rename
(
cp_old_name
)
def
failover
(
self
):
try
:
self
.
_failover
()
log
.
info
(
'Renaming done'
)
except
slapos
.
slap
.
slap
.
ServerError
:
log
.
info
(
'Internal server error'
)
## Leader is always number 0
class
ResilientInstance
(
object
):
def
__init__
(
self
,
comm
,
renamer
,
confpath
):
self
.
comm
=
comm
self
.
id
=
0
self
.
state
=
'normal'
self
.
halter
=
0
self
.
inElection
=
False
self
.
alive
=
True
self
.
lastPing
=
time
.
clock
()
self
.
mainCanal
=
self
.
comm
.
canal
([
'ping'
,
'halt'
,
'victory'
])
self
.
renamer
=
renamer
self
.
okCanal
=
self
.
comm
.
canal
([
'ok'
])
self
.
confpath
=
confpath
self
.
loadConnectionInfo
()
def
loadConnectionInfo
(
self
):
file
=
open
(
self
.
confpath
,
'r'
)
params
=
file
.
read
().
split
(
'
\
n
'
)
file
.
close
()
self
.
nbComp
=
len
([
x
.
strip
(
"' "
)
for
x
in
params
[
0
].
strip
(
'[],'
).
split
(
','
)])
new_id
=
int
(
params
[
1
])
if
self
.
id
!=
new_id
:
self
.
halter
=
new_id
self
.
id
=
new_id
## Needs to be changed to use the master
def
aliveManagement
(
self
):
while
self
.
alive
:
log
.
info
(
'XXX sleeping for %d minutes'
%
SLEEPING_MINS
)
time
.
sleep
(
SLEEPING_MINS
*
60
)
if
self
.
id
==
0
:
continue
self
.
comm
.
send
(
'ping'
,
0
)
message
,
sender
=
self
.
okCanal
.
get
()
if
message
:
continue
self
.
election
()
def
listen
(
self
):
while
self
.
alive
:
self
.
comm
.
recv
()
def
main
(
self
):
while
self
.
alive
:
message
,
sender
=
self
.
mainCanal
.
get
()
if
message
==
'ping'
:
self
.
comm
.
send
(
'ok'
,
sender
)
elif
message
==
'halt'
:
self
.
state
=
'waitingConfirm'
self
.
halter
=
sender
self
.
comm
.
send
(
'ok'
,
sender
)
elif
message
==
'victory'
:
if
int
(
sender
)
==
int
(
self
.
halter
)
and
self
.
state
==
'waitingConfirm'
:
log
.
info
(
'{} thinks {} is the leader'
.
format
(
self
.
id
,
sender
))
self
.
comm
.
send
(
'ok'
,
sender
)
self
.
state
=
'normal'
def
election
(
self
):
self
.
inElection
=
True
self
.
loadConnectionInfo
()
#Check if I'm the highest instance alive
for
higher
in
range
(
self
.
id
+
1
,
self
.
nbComp
):
self
.
comm
.
send
(
'ping'
,
higher
)
message
,
sender
=
self
.
okCanal
.
get
()
if
message
:
log
.
info
(
'{} is alive ({})'
.
format
(
higher
,
self
.
id
))
self
.
inElection
=
False
return
False
continue
if
not
self
.
alive
:
return
False
#I should be the new coordinator, halt those below me
log
.
info
(
'Should be ME : {}'
.
format
(
self
.
id
))
self
.
state
=
'election'
self
.
halter
=
self
.
id
ups
=
[]
for
lower
in
range
(
self
.
id
):
self
.
comm
.
send
(
'halt'
,
lower
)
message
,
sender
=
self
.
okCanal
.
get
()
if
message
:
ups
.
append
(
lower
)
#Broadcast Victory
self
.
state
=
'reorganization'
for
up
in
ups
:
self
.
comm
.
send
(
'victory'
,
up
)
message
,
sender
=
self
.
okCanal
.
get
()
if
message
:
continue
log
.
info
(
'Something is wrong... let
\
'
s start over'
)
return
self
.
election
()
self
.
state
=
'normal'
self
.
active
=
True
log
.
info
(
'{} Is THE LEADER'
.
format
(
self
.
id
))
self
.
renamer
.
failover
()
self
.
inElection
=
False
return
True
class
FilteredCanal
(
object
):
def
__init__
(
self
,
accept
,
timeout
):
self
.
accept
=
accept
self
.
list
=
[]
self
.
lock
=
thread
.
allocate_lock
()
self
.
timeout
=
timeout
def
append
(
self
,
message
,
sender
):
if
message
in
self
.
accept
:
self
.
lock
.
acquire
()
self
.
list
.
append
([
message
,
sender
])
self
.
lock
.
release
()
def
get
(
self
):
start
=
time
.
clock
()
while
(
time
.
clock
()
-
start
<
self
.
timeout
):
self
.
lock
.
acquire
()
if
self
.
list
:
self
.
lock
.
release
()
return
self
.
list
.
pop
(
0
)
self
.
lock
.
release
()
return
[
None
,
None
]
class
Wrapper
(
object
):
def
__init__
(
self
,
confpath
,
timeout
=
20
):
self
.
canals
=
[]
self
.
ips
=
[]
self
.
id
=
0
self
.
timeout
=
timeout
self
.
confpath
=
confpath
self
.
getConnectionInfo
()
self
.
socket
=
None
def
getConnectionInfo
(
self
):
file
=
open
(
self
.
confpath
,
'r'
)
params
=
file
.
read
().
split
(
'
\
n
'
)
file
.
close
()
self
.
ips
=
[
x
.
strip
(
"' "
)
for
x
in
params
[
0
].
strip
(
'[],'
).
split
(
','
)]
self
.
id
=
int
(
params
[
1
])
def
start
(
self
):
self
.
getConnectionInfo
()
self
.
socket
=
socket
.
socket
(
socket
.
AF_INET6
,
socket
.
SOCK_STREAM
)
self
.
socket
.
bind
((
self
.
ips
[
self
.
id
],
BASE_PORT
+
self
.
id
))
self
.
socket
.
listen
(
5
)
def
send
(
self
,
message
,
number
):
self
.
getConnectionInfo
()
try
:
s
=
socket
.
socket
(
socket
.
AF_INET6
,
socket
.
SOCK_STREAM
)
s
.
connect
((
self
.
ips
[
number
],
BASE_PORT
+
number
))
s
.
send
(
message
+
(
' {}
\
n
'
.
format
(
self
.
id
)))
except
(
socket
.
error
,
socket
.
herror
,
socket
.
gaierror
,
socket
.
timeout
):
pass
finally
:
s
.
close
()
def
canal
(
self
,
accept
):
created
=
FilteredCanal
(
accept
,
self
.
timeout
)
self
.
canals
.
append
(
created
)
return
created
def
recv
(
self
):
client
,
_
=
self
.
socket
.
accept
()
client_message
=
client
.
recv
(
1024
)
if
client_message
:
message
,
sender
=
client_message
.
split
()
for
canal
in
self
.
canals
:
canal
.
append
(
message
,
int
(
sender
))
def
run
(
args
):
confpath
=
args
.
pop
(
'confpath'
)
renamer
=
Renamer
(
server_url
=
args
.
pop
(
'server_url'
),
key_file
=
args
.
pop
(
'key_file'
),
cert_file
=
args
.
pop
(
'cert_file'
),
computer_guid
=
args
.
pop
(
'computer_id'
),
partition_id
=
args
.
pop
(
'partition_id'
),
software_release
=
args
.
pop
(
'software'
),
namebase
=
args
.
pop
(
'namebase'
))
if
args
:
raise
ValueError
(
'Unknown arguments: %s'
%
', '
.
join
(
args
))
wrapper
=
Wrapper
(
confpath
=
confpath
,
timeout
=
20
)
computer
=
ResilientInstance
(
wrapper
,
renamer
=
renamer
,
confpath
=
confpath
)
# idle waiting for connection infos
while
computer
.
nbComp
<
2
:
computer
.
loadConnectionInfo
()
time
.
sleep
(
30
)
log
.
info
(
'Starting'
)
computer
.
comm
.
start
()
thread
.
start_new_thread
(
computer
.
listen
,
())
thread
.
start_new_thread
(
computer
.
main
,
())
thread
.
start_new_thread
(
computer
.
aliveManagement
,
())
while
True
:
# XXX tight loop
continue
slapos/recipe/addresiliency/template/
conf.in
.in
→
slapos/recipe/addresiliency/template/
bully.conf
.in
View file @
728d2e39
File moved
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