Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
slapos.core
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
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Romain Courteaud
slapos.core
Commits
9c0d587c
Commit
9c0d587c
authored
Feb 08, 2013
by
Cédric de Saint Martin
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/slapformat'
parents
2d8c4212
87663a71
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
240 additions
and
165 deletions
+240
-165
slapos/entry.py
slapos/entry.py
+1
-0
slapos/format.py
slapos/format.py
+239
-165
No files found.
slapos/entry.py
View file @
9c0d587c
...
@@ -115,6 +115,7 @@ def dispatch(command, is_node_command):
...
@@ -115,6 +115,7 @@ def dispatch(command, is_node_command):
If configuration file is not given: define it arbitrarily, and so on.
If configuration file is not given: define it arbitrarily, and so on.
"""
"""
if
is_node_command
:
if
is_node_command
:
# XXX-Cedric: should we check if we are root?
if
command
==
'register'
:
if
command
==
'register'
:
call
(
register
)
call
(
register
)
elif
command
==
'software'
:
elif
command
==
'software'
:
...
...
slapos/format.py
View file @
9c0d587c
...
@@ -34,6 +34,7 @@ import ConfigParser
...
@@ -34,6 +34,7 @@ import ConfigParser
import
errno
import
errno
import
fcntl
import
fcntl
import
grp
import
grp
import
json
import
logging
import
logging
import
netaddr
import
netaddr
import
netifaces
import
netifaces
...
@@ -50,6 +51,7 @@ import time
...
@@ -50,6 +51,7 @@ import time
import
zipfile
import
zipfile
import
lxml.etree
import
lxml.etree
from
slapos.version
import
version
def
prettify_xml
(
xml
):
def
prettify_xml
(
xml
):
...
@@ -58,6 +60,8 @@ def prettify_xml(xml):
...
@@ -58,6 +60,8 @@ def prettify_xml(xml):
class
OS
(
object
):
class
OS
(
object
):
"""Wrap parts of the 'os' module to provide logging of performed actions."""
_os
=
os
_os
=
os
def
__init__
(
self
,
config
):
def
__init__
(
self
,
config
):
...
@@ -74,11 +78,9 @@ class OS(object):
...
@@ -74,11 +78,9 @@ class OS(object):
def
wrapper
(
*
args
,
**
kw
):
def
wrapper
(
*
args
,
**
kw
):
if
self
.
_verbose
:
if
self
.
_verbose
:
arg_list
=
[
repr
(
x
)
for
x
in
args
]
+
[
arg_list
=
[
repr
(
x
)
for
x
in
args
]
+
[
'%s=%r'
%
(
x
,
y
)
for
x
,
y
in
kw
.
iteritems
()]
'%s=%r'
%
(
x
,
y
)
for
x
,
y
in
kw
.
iteritems
()
self
.
_logger
.
debug
(
'%s(%s)'
%
(
]
name
,
self
.
_logger
.
debug
(
'%s(%s)'
%
(
name
,
', '
.
join
(
arg_list
)))
', '
.
join
(
arg_list
)
))
if
not
self
.
_dry_run
:
if
not
self
.
_dry_run
:
getattr
(
self
.
_os
,
name
)(
*
args
,
**
kw
)
getattr
(
self
.
_os
,
name
)(
*
args
,
**
kw
)
setattr
(
self
,
name
,
wrapper
)
setattr
(
self
,
name
,
wrapper
)
...
@@ -86,12 +88,14 @@ class OS(object):
...
@@ -86,12 +88,14 @@ class OS(object):
def
__getattr__
(
self
,
name
):
def
__getattr__
(
self
,
name
):
return
getattr
(
self
.
_os
,
name
)
return
getattr
(
self
.
_os
,
name
)
class
UsageError
(
Exception
):
class
UsageError
(
Exception
):
pass
pass
class
NoAddressOnInterface
(
Exception
):
class
NoAddressOnInterface
(
Exception
):
"""
"""
Exception raised if there
's not
address on the interface to construct IPv6
Exception raised if there
is no
address on the interface to construct IPv6
address with.
address with.
Attributes:
Attributes:
...
@@ -100,9 +104,10 @@ class NoAddressOnInterface(Exception):
...
@@ -100,9 +104,10 @@ class NoAddressOnInterface(Exception):
def
__init__
(
self
,
interface
):
def
__init__
(
self
,
interface
):
super
(
NoAddressOnInterface
,
self
).
__init__
(
super
(
NoAddressOnInterface
,
self
).
__init__
(
'No IPv6 found on interface %s to construct IPv6 with.'
%
(
interface
,
)
'No IPv6 found on interface %s to construct IPv6 with.'
%
interface
)
)
class
AddressGenerationError
(
Exception
):
class
AddressGenerationError
(
Exception
):
"""
"""
Exception raised if the generation of an IPv6 based on the prefix obtained
Exception raised if the generation of an IPv6 based on the prefix obtained
...
@@ -116,31 +121,37 @@ class AddressGenerationError(Exception):
...
@@ -116,31 +121,37 @@ class AddressGenerationError(Exception):
'Generated IPv6 %s seems not to be a valid IP.'
%
addr
'Generated IPv6 %s seems not to be a valid IP.'
%
addr
)
)
def
callAndRead
(
argument_list
,
raise_on_error
=
True
):
def
callAndRead
(
argument_list
,
raise_on_error
=
True
):
popen
=
subprocess
.
Popen
(
argument_list
,
stdout
=
subprocess
.
PIPE
,
popen
=
subprocess
.
Popen
(
argument_list
,
stderr
=
subprocess
.
STDOUT
)
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
result
=
popen
.
communicate
()[
0
]
result
=
popen
.
communicate
()[
0
]
if
raise_on_error
and
popen
.
returncode
!=
0
:
if
raise_on_error
and
popen
.
returncode
!=
0
:
raise
ValueError
(
'Issue while invoking %r, result was:
\
n
%s'
%
(
raise
ValueError
(
'Issue while invoking %r, result was:
\
n
%s'
%
(
argument_list
,
result
))
argument_list
,
result
))
return
popen
.
returncode
,
result
return
popen
.
returncode
,
result
def
isGlobalScopeAddress
(
a
):
def
isGlobalScopeAddress
(
a
):
"""Returns True if a is global scope IP v4/6 address"""
"""Returns True if a is global scope IP v4/6 address"""
ip
=
netaddr
.
IPAddress
(
a
)
ip
=
netaddr
.
IPAddress
(
a
)
return
not
ip
.
is_link_local
()
and
not
ip
.
is_loopback
()
and
\
return
not
ip
.
is_link_local
()
and
not
ip
.
is_loopback
()
and
\
not
ip
.
is_reserved
()
and
ip
.
is_unicast
()
not
ip
.
is_reserved
()
and
ip
.
is_unicast
()
def
netmaskToPrefixIPv4
(
netmask
):
def
netmaskToPrefixIPv4
(
netmask
):
"""Convert string represented netmask to its integer prefix"""
"""Convert string represented netmask to its integer prefix"""
return
netaddr
.
strategy
.
ipv4
.
netmask_to_prefix
[
return
netaddr
.
strategy
.
ipv4
.
netmask_to_prefix
[
netaddr
.
strategy
.
ipv4
.
str_to_int
(
netmask
)]
netaddr
.
strategy
.
ipv4
.
str_to_int
(
netmask
)]
def
netmaskToPrefixIPv6
(
netmask
):
def
netmaskToPrefixIPv6
(
netmask
):
"""Convert string represented netmask to its integer prefix"""
"""Convert string represented netmask to its integer prefix"""
return
netaddr
.
strategy
.
ipv6
.
netmask_to_prefix
[
return
netaddr
.
strategy
.
ipv6
.
netmask_to_prefix
[
netaddr
.
strategy
.
ipv6
.
str_to_int
(
netmask
)]
netaddr
.
strategy
.
ipv6
.
str_to_int
(
netmask
)]
def
_getDict
(
instance
):
def
_getDict
(
instance
):
"""
"""
Serialize an object instance into dictionaries. List and dict will remains
Serialize an object instance into dictionaries. List and dict will remains
...
@@ -172,13 +183,14 @@ def _getDict(instance):
...
@@ -172,13 +183,14 @@ def _getDict(instance):
result
[
key
]
=
_getDict
(
value
)
result
[
key
]
=
_getDict
(
value
)
return
result
return
result
class
Computer
(
object
):
class
Computer
(
object
):
"Object representing the computer"
"Object representing the computer"
instance_root
=
None
instance_root
=
None
software_root
=
None
software_root
=
None
def
__init__
(
self
,
reference
,
interface
=
None
,
addr
=
None
,
netmask
=
None
,
def
__init__
(
self
,
reference
,
interface
=
None
,
addr
=
None
,
netmask
=
None
,
ipv6_interface
=
None
,
software_user
=
'slapsoft'
):
ipv6_interface
=
None
,
software_user
=
'slapsoft'
):
"""
"""
Attributes:
Attributes:
reference: String, the reference of the computer.
reference: String, the reference of the computer.
...
@@ -197,14 +209,14 @@ class Computer(object):
...
@@ -197,14 +209,14 @@ class Computer(object):
def
getAddress
(
self
,
allow_tap
=
False
):
def
getAddress
(
self
,
allow_tap
=
False
):
"""
"""
Return a list of the interface address not attributed to any partition
,
(which
Return a list of the interface address not attributed to any partition (which
are therefore free for the computer itself).
are therefore free for the computer itself).
Returns:
Returns:
False if the interface isn't available, else the list of the free addresses.
False if the interface isn't available, else the list of the free addresses.
"""
"""
if
self
.
interface
is
None
:
if
self
.
interface
is
None
:
return
dict
(
addr
=
self
.
address
,
netmask
=
self
.
netmask
)
return
{
'addr'
:
self
.
address
,
'netmask'
:
self
.
netmask
}
computer_partition_address_list
=
[]
computer_partition_address_list
=
[]
for
partition
in
self
.
partition_list
:
for
partition
in
self
.
partition_list
:
...
@@ -218,15 +230,14 @@ class Computer(object):
...
@@ -218,15 +230,14 @@ class Computer(object):
return
address_dict
return
address_dict
if
allow_tap
:
if
allow_tap
:
# all addresses on interface are for partition, so lets add new one
# all addresses on interface are for partition, so let
'
s add new one
computer_tap
=
Tap
(
'compdummy'
)
computer_tap
=
Tap
(
'compdummy'
)
computer_tap
.
createWithOwner
(
User
(
'root'
),
attach_to_tap
=
True
)
computer_tap
.
createWithOwner
(
User
(
'root'
),
attach_to_tap
=
True
)
self
.
interface
.
addTap
(
computer_tap
)
self
.
interface
.
addTap
(
computer_tap
)
return
self
.
interface
.
addAddr
()
return
self
.
interface
.
addAddr
()
# Can't find address
# Can't find address
raise
NoAddressOnInterface
(
'No valid IPv6 found on %s.'
%
raise
NoAddressOnInterface
(
'No valid IPv6 found on %s.'
%
self
.
interface
.
name
)
self
.
interface
.
name
)
def
send
(
self
,
config
):
def
send
(
self
,
config
):
"""
"""
...
@@ -236,12 +247,12 @@ class Computer(object):
...
@@ -236,12 +247,12 @@ class Computer(object):
slap_instance
=
slap
.
slap
()
slap_instance
=
slap
.
slap
()
connection_dict
=
{}
connection_dict
=
{}
if
config
.
key_file
and
config
.
cert_file
:
if
config
.
key_file
and
config
.
cert_file
:
connection_dict
.
update
(
connection_dict
[
'key_file'
]
=
config
.
key_file
key_file
=
config
.
key_file
,
connection_dict
[
'cert_file'
]
=
config
.
cert_file
cert_file
=
config
.
cert_file
)
slap_instance
.
initializeConnection
(
config
.
master_url
,
slap_instance
.
initializeConnection
(
config
.
master_url
,
**
connection_dict
)
**
connection_dict
)
slap_computer
=
slap_instance
.
registerComputer
(
self
.
reference
)
slap_computer
=
slap_instance
.
registerComputer
(
self
.
reference
)
if
config
.
dry_run
:
if
config
.
dry_run
:
return
return
try
:
try
:
...
@@ -250,19 +261,22 @@ class Computer(object):
...
@@ -250,19 +261,22 @@ class Computer(object):
raise
slap
.
NotFoundError
(
"%s
\
n
ERROR : This SlapOS node is not recognised by "
raise
slap
.
NotFoundError
(
"%s
\
n
ERROR : This SlapOS node is not recognised by "
"SlapOS Master. Please make sure computer_id of slapos.cfg looks "
"SlapOS Master. Please make sure computer_id of slapos.cfg looks "
"like 'COMP-123' and is correct.
\
n
Error is : 404 Not Found."
%
error
)
"like 'COMP-123' and is correct.
\
n
Error is : 404 Not Found."
%
error
)
return
def
dump
(
self
,
path_to_xml
):
def
dump
(
self
,
path_to_xml
,
path_to_json
):
"""
"""
Dump the computer object to an xml file via xml_marshaller.
Dump the computer object to an xml file via xml_marshaller.
Args:
Args:
path_to_xml: String, path to the file to load.
path_to_xml: String, path to the file to load.
users: List of User, list of user needed to be add to the dump
path_to_json: String, path to the JSON version to save.
(even if they are not related to any tap interface).
"""
"""
computer_dict
=
_getDict
(
self
)
computer_dict
=
_getDict
(
self
)
if
path_to_json
:
with
open
(
path_to_json
,
'wb'
)
as
fout
:
fout
.
write
(
json
.
dumps
(
computer_dict
,
sort_keys
=
True
,
indent
=
2
))
new_xml
=
xml_marshaller
.
dumps
(
computer_dict
)
new_xml
=
xml_marshaller
.
dumps
(
computer_dict
)
new_pretty_xml
=
prettify_xml
(
new_xml
)
new_pretty_xml
=
prettify_xml
(
new_xml
)
...
@@ -275,13 +289,17 @@ class Computer(object):
...
@@ -275,13 +289,17 @@ class Computer(object):
# computer configuration did not change, nothing to write
# computer configuration did not change, nothing to write
return
return
self
.
backup_xml
(
path_to_archive
,
path_to_xml
)
if
os
.
path
.
exists
(
path_to_xml
):
self
.
backup_xml
(
path_to_archive
,
path_to_xml
)
with
open
(
path_to_xml
,
'wb'
)
as
fout
:
with
open
(
path_to_xml
,
'wb'
)
as
fout
:
fout
.
write
(
new_pretty_xml
)
fout
.
write
(
new_pretty_xml
)
def
backup_xml
(
self
,
path_to_archive
,
path_to_xml
):
def
backup_xml
(
self
,
path_to_archive
,
path_to_xml
):
"""
Stores a copy of the current xml file to an historical archive.
"""
xml_content
=
open
(
path_to_xml
).
read
()
xml_content
=
open
(
path_to_xml
).
read
()
saved_filename
=
os
.
path
.
basename
(
path_to_xml
)
+
time
.
strftime
(
'.%Y%m%d-%H:%M'
)
saved_filename
=
os
.
path
.
basename
(
path_to_xml
)
+
time
.
strftime
(
'.%Y%m%d-%H:%M'
)
...
@@ -309,8 +327,8 @@ class Computer(object):
...
@@ -309,8 +327,8 @@ class Computer(object):
reference
=
reference
,
reference
=
reference
,
addr
=
dumped_dict
[
'address'
],
addr
=
dumped_dict
[
'address'
],
netmask
=
dumped_dict
[
'netmask'
],
netmask
=
dumped_dict
[
'netmask'
],
ipv6_interface
=
ipv6_interface
,
ipv6_interface
=
ipv6_interface
,
software_user
=
dumped_dict
.
get
(
'software_user'
,
'slapsoft'
),
software_user
=
dumped_dict
.
get
(
'software_user'
,
'slapsoft'
),
)
)
for
partition_dict
in
dumped_dict
[
'partition_list'
]:
for
partition_dict
in
dumped_dict
[
'partition_list'
]:
...
@@ -411,6 +429,7 @@ class Computer(object):
...
@@ -411,6 +429,7 @@ class Computer(object):
if
not
any
([
netaddr
.
valid_ipv4
(
q
[
'addr'
])
if
not
any
([
netaddr
.
valid_ipv4
(
q
[
'addr'
])
for
q
in
old_partition_address_list
]):
for
q
in
old_partition_address_list
]):
raise
ValueError
(
'Not valid ipv6 addresses loaded'
)
raise
ValueError
(
'Not valid ipv6 addresses loaded'
)
for
address
in
old_partition_address_list
:
for
address
in
old_partition_address_list
:
if
netaddr
.
valid_ipv6
(
address
[
'addr'
]):
if
netaddr
.
valid_ipv6
(
address
[
'addr'
]):
partition
.
address_list
.
append
(
self
.
interface
.
addAddr
(
partition
.
address_list
.
append
(
self
.
interface
.
addAddr
(
...
@@ -428,6 +447,7 @@ class Computer(object):
...
@@ -428,6 +447,7 @@ class Computer(object):
except
IndexError
:
except
IndexError
:
pass
pass
class
Partition
(
object
):
class
Partition
(
object
):
"Represent a computer partition"
"Represent a computer partition"
...
@@ -465,8 +485,10 @@ class Partition(object):
...
@@ -465,8 +485,10 @@ class Partition(object):
os
.
chown
(
self
.
path
,
owner_pw
.
pw_uid
,
owner_pw
.
pw_gid
)
os
.
chown
(
self
.
path
,
owner_pw
.
pw_uid
,
owner_pw
.
pw_gid
)
os
.
chmod
(
self
.
path
,
0750
)
os
.
chmod
(
self
.
path
,
0750
)
class
User
(
object
):
class
User
(
object
):
"User: represent and manipulate a user on the system."
"""User: represent and manipulate a user on the system."""
path
=
None
path
=
None
def
__init__
(
self
,
user_name
,
additional_group_list
=
None
):
def
__init__
(
self
,
user_name
,
additional_group_list
=
None
):
...
@@ -526,7 +548,6 @@ class User(object):
...
@@ -526,7 +548,6 @@ class User(object):
try
:
try
:
pwd
.
getpwnam
(
self
.
name
)
pwd
.
getpwnam
(
self
.
name
)
return
True
return
True
except
KeyError
:
except
KeyError
:
return
False
return
False
...
@@ -551,7 +572,7 @@ class Tap(object):
...
@@ -551,7 +572,7 @@ class Tap(object):
def
attach
(
self
):
def
attach
(
self
):
"""
"""
Attach to the TAP interface, meaning that it just opens the TAP interface
Attach to the TAP interface, meaning that it just opens the TAP interface
and wait for the caller to notify that it can be safely detached.
and wait
s
for the caller to notify that it can be safely detached.
Linux distinguishes administrative and operational state of an network
Linux distinguishes administrative and operational state of an network
interface. The former can be set manually by running ``ip link set dev
interface. The former can be set manually by running ``ip link set dev
...
@@ -579,7 +600,7 @@ class Tap(object):
...
@@ -579,7 +600,7 @@ class Tap(object):
fcntl
.
ioctl
(
tap_fd
,
self
.
TUNSETIFF
,
fcntl
.
ioctl
(
tap_fd
,
self
.
TUNSETIFF
,
struct
.
pack
(
"16sI"
,
self
.
name
,
self
.
IFF_TAP
))
struct
.
pack
(
"16sI"
,
self
.
name
,
self
.
IFF_TAP
))
except
IOError
,
error
:
except
IOError
as
error
:
# If EBUSY, it means another program is already attached, thus just
# If EBUSY, it means another program is already attached, thus just
# ignore it...
# ignore it...
if
error
.
errno
!=
errno
.
EBUSY
:
if
error
.
errno
!=
errno
.
EBUSY
:
...
@@ -622,8 +643,9 @@ class Tap(object):
...
@@ -622,8 +643,9 @@ class Tap(object):
if
attach_to_tap
:
if
attach_to_tap
:
threading
.
Thread
(
target
=
self
.
attach
).
start
()
threading
.
Thread
(
target
=
self
.
attach
).
start
()
class
Interface
(
object
):
class
Interface
(
object
):
"
Interface represent a interface on the system
"
"
""Represent a network interface on the system""
"
def
__init__
(
self
,
name
,
ipv4_local_network
,
ipv6_interface
=
None
):
def
__init__
(
self
,
name
,
ipv4_local_network
,
ipv6_interface
=
None
):
"""
"""
...
@@ -640,6 +662,9 @@ class Interface(object):
...
@@ -640,6 +662,9 @@ class Interface(object):
_
,
result
=
callAndRead
([
'ip'
,
'addr'
,
'list'
,
self
.
name
])
_
,
result
=
callAndRead
([
'ip'
,
'addr'
,
'list'
,
self
.
name
])
self
.
attach_to_tap
=
'DOWN'
in
result
.
split
(
'
\
n
'
,
1
)[
0
]
self
.
attach_to_tap
=
'DOWN'
in
result
.
split
(
'
\
n
'
,
1
)[
0
]
# XXX-Cedric should be global logger
self
.
logger
=
logging
.
getLogger
(
"slapformat"
)
def
__getinitargs__
(
self
):
def
__getinitargs__
(
self
):
return
(
self
.
name
,)
return
(
self
.
name
,)
...
@@ -735,7 +760,8 @@ class Interface(object):
...
@@ -735,7 +760,8 @@ class Interface(object):
if
not
af
in
netifaces
.
ifaddresses
(
interface_name
)
\
if
not
af
in
netifaces
.
ifaddresses
(
interface_name
)
\
or
not
address
in
[
q
[
'addr'
].
split
(
'%'
)[
0
]
or
not
address
in
[
q
[
'addr'
].
split
(
'%'
)[
0
]
for
q
in
netifaces
.
ifaddresses
(
interface_name
)[
af
]]:
for
q
in
netifaces
.
ifaddresses
(
interface_name
)[
af
]
]:
# add an address
# add an address
callAndRead
([
'ip'
,
'addr'
,
'add'
,
address_string
,
'dev'
,
interface_name
])
callAndRead
([
'ip'
,
'addr'
,
'add'
,
address_string
,
'dev'
,
interface_name
])
...
@@ -745,14 +771,18 @@ class Interface(object):
...
@@ -745,14 +771,18 @@ class Interface(object):
# wait few moments
# wait few moments
time
.
sleep
(
2
)
time
.
sleep
(
2
)
# check existence on interface
# Fake success for local ipv4
if
not
ipv6
:
return
True
# check existence on interface for ipv6
_
,
result
=
callAndRead
([
'ip'
,
'addr'
,
'list'
,
interface_name
])
_
,
result
=
callAndRead
([
'ip'
,
'addr'
,
'list'
,
interface_name
])
for
l
in
result
.
split
(
'
\
n
'
):
for
l
in
result
.
split
(
'
\
n
'
):
if
address
in
l
:
if
address
in
l
:
if
'tentative'
in
l
:
if
'tentative'
in
l
:
# duplicate, remove
# duplicate, remove
callAndRead
([
'ip'
,
'addr'
,
'del'
,
address_string
,
'dev'
,
callAndRead
([
'ip'
,
'addr'
,
'del'
,
address_string
,
'dev'
,
interface_name
])
interface_name
])
return
False
return
False
# found and clean
# found and clean
return
True
return
True
...
@@ -785,6 +815,8 @@ class Interface(object):
...
@@ -785,6 +815,8 @@ class Interface(object):
if
self
.
_addSystemAddress
(
addr
,
netmask
,
False
):
if
self
.
_addSystemAddress
(
addr
,
netmask
,
False
):
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
else
:
else
:
self
.
logger
.
warning
(
'Impossible to add old local IPv4 %s. Generating '
'new IPv4 address.'
%
addr
)
return
self
.
_generateRandomIPv4Address
(
netmask
)
return
self
.
_generateRandomIPv4Address
(
netmask
)
else
:
else
:
# confirmed to be configured
# confirmed to be configured
...
@@ -840,6 +872,9 @@ class Interface(object):
...
@@ -840,6 +872,9 @@ class Interface(object):
if
self
.
_addSystemAddress
(
addr
,
netmask
):
if
self
.
_addSystemAddress
(
addr
,
netmask
):
# succeed, return it
# succeed, return it
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
else
:
self
.
logger
.
warning
(
'Impossible to add old public IPv6 %s. '
'Generating new IPv6 address.'
%
addr
)
# Try 10 times to add address, raise in case if not possible
# Try 10 times to add address, raise in case if not possible
try_num
=
10
try_num
=
10
...
@@ -857,11 +892,12 @@ class Interface(object):
...
@@ -857,11 +892,12 @@ class Interface(object):
raise
AddressGenerationError
(
addr
)
raise
AddressGenerationError
(
addr
)
class
Parser
(
OptionParser
):
class
Parser
(
OptionParser
):
"""
"""
Parse all arguments.
Parse all arguments.
"""
"""
def
__init__
(
self
,
usage
=
None
,
version
=
None
):
def
__init__
(
self
,
usage
=
None
,
version
=
version
):
"""
"""
Initialize all options possibles.
Initialize all options possibles.
"""
"""
...
@@ -872,6 +908,10 @@ class Parser(OptionParser):
...
@@ -872,6 +908,10 @@ class Parser(OptionParser):
"will be created"
,
"will be created"
,
default
=
None
,
default
=
None
,
type
=
str
),
type
=
str
),
Option
(
"--computer_json"
,
help
=
"Path to a JSON version of the computer's XML (for development only)."
,
default
=
None
,
type
=
str
),
Option
(
"-l"
,
"--log_file"
,
Option
(
"-l"
,
"--log_file"
,
help
=
"The path to the log file used by the script."
,
help
=
"The path to the log file used by the script."
,
type
=
str
),
type
=
str
),
...
@@ -919,100 +959,128 @@ class Parser(OptionParser):
...
@@ -919,100 +959,128 @@ class Parser(OptionParser):
self
.
error
(
"Incorrect number of arguments"
)
self
.
error
(
"Incorrect number of arguments"
)
return
options
,
args
[
0
]
return
options
,
args
[
0
]
def
run
(
config
):
# Define the computer
if
config
.
input_definition_file
:
def
parse_computer_definition
(
config
,
definition_path
):
filepath
=
os
.
path
.
abspath
(
config
.
input_definition_file
)
config
.
logger
.
info
(
'Using definition file %r'
%
definition_path
)
config
.
logger
.
info
(
'Using definition file %r'
%
filepath
)
computer_definition
=
ConfigParser
.
RawConfigParser
({
computer_definition
=
ConfigParser
.
RawConfigParser
({
'software_user'
:
'slapsoft'
,
'software_user'
:
'slapsoft'
,
})
})
computer_definition
.
read
(
definition_path
)
computer_definition
.
read
(
filepath
)
interface
=
None
interface
=
None
address
=
None
address
=
None
netmask
=
None
netmask
=
None
if
computer_definition
.
has_option
(
'computer'
,
'address'
):
if
computer_definition
.
has_option
(
'computer'
,
'address'
):
address
,
netmask
=
computer_definition
.
get
(
'computer'
,
'address'
).
split
(
'/'
)
address
,
netmask
=
computer_definition
.
get
(
'computer'
,
if
config
.
alter_network
and
config
.
interface_name
is
not
None
\
'address'
).
split
(
'/'
)
and
config
.
ipv4_local_network
is
not
None
:
if
config
.
alter_network
and
config
.
interface_name
is
not
None
\
interface
=
Interface
(
config
.
interface_name
,
config
.
ipv4_local_network
,
and
config
.
ipv4_local_network
is
not
None
:
config
.
ipv6_interface
)
interface
=
Interface
(
config
.
interface_name
,
config
.
ipv4_local_network
,
computer
=
Computer
(
reference
=
config
.
computer_id
,
interface
=
interface
,
addr
=
address
,
netmask
=
netmask
,
ipv6_interface
=
config
.
ipv6_interface
,
software_user
=
computer_definition
.
get
(
'computer'
,
'software_user'
),
)
partition_list
=
[]
for
partition_number
in
range
(
int
(
config
.
partition_amount
)):
section
=
'partition_%s'
%
partition_number
user
=
User
(
computer_definition
.
get
(
section
,
'user'
))
address_list
=
[]
for
a
in
computer_definition
.
get
(
section
,
'address'
).
split
():
address
,
netmask
=
a
.
split
(
'/'
)
address_list
.
append
(
dict
(
addr
=
address
,
netmask
=
netmask
))
tap
=
Tap
(
computer_definition
.
get
(
section
,
'network_interface'
))
partition
=
Partition
(
reference
=
computer_definition
.
get
(
section
,
'pathname'
),
path
=
os
.
path
.
join
(
config
.
instance_root
,
computer_definition
.
get
(
section
,
'pathname'
)),
user
=
user
,
address_list
=
address_list
,
tap
=
tap
)
partition_list
.
append
(
partition
)
computer
.
partition_list
=
partition_list
return
computer
def
parse_computer_xml
(
config
,
xml_path
):
if
os
.
path
.
exists
(
xml_path
):
config
.
logger
.
info
(
'Loading previous computer data from %r'
%
xml_path
)
computer
=
Computer
.
load
(
xml_path
,
reference
=
config
.
computer_id
,
ipv6_interface
=
config
.
ipv6_interface
)
# Connect to the interface defined by the configuration
computer
.
interface
=
Interface
(
config
.
interface_name
,
config
.
ipv4_local_network
,
config
.
ipv6_interface
)
config
.
ipv6_interface
)
else
:
# If no pre-existent configuration found, create a new computer object
config
.
logger
.
warning
(
'Creating new data computer with id %r'
%
config
.
computer_id
)
computer
=
Computer
(
computer
=
Computer
(
reference
=
config
.
computer_id
,
reference
=
config
.
computer_id
,
interface
=
interface
,
interface
=
Interface
(
config
.
interface_name
,
config
.
ipv4_local_network
,
addr
=
address
,
config
.
ipv6_interface
),
netmask
=
netmask
,
addr
=
None
,
ipv6_interface
=
config
.
ipv6_interface
,
netmask
=
None
,
software_user
=
computer_definition
.
get
(
'computer'
,
'software_user'
),
ipv6_interface
=
config
.
ipv6_interface
,
)
software_user
=
config
.
software_user
,
partition_list
=
[]
)
for
partition_number
in
range
(
int
(
config
.
partition_amount
)):
section
=
'partition_%s'
%
partition_number
partition_amount
=
int
(
config
.
partition_amount
)
user
=
User
(
computer_definition
.
get
(
section
,
'user'
))
existing_partition_amount
=
len
(
computer
.
partition_list
)
address_list
=
[]
if
existing_partition_amount
>
partition_amount
:
for
a
in
computer_definition
.
get
(
section
,
'address'
).
split
():
raise
ValueError
(
'Requested amount of computer partitions (%s) is lower '
address
,
netmask
=
a
.
split
(
'/'
)
'then already configured (%s), cannot continue'
%
(
partition_amount
,
address_list
.
append
(
dict
(
addr
=
address
,
netmask
=
netmask
))
len
(
computer
.
partition_list
)))
tap
=
Tap
(
computer_definition
.
get
(
section
,
'network_interface'
))
partition_list
.
append
(
Partition
(
reference
=
computer_definition
.
get
(
config
.
logger
.
info
(
'Adding %s new partitions'
%
section
,
'pathname'
),
(
partition_amount
-
existing_partition_amount
))
path
=
os
.
path
.
join
(
config
.
instance_root
,
computer_definition
.
get
(
for
nb_iter
in
range
(
existing_partition_amount
,
partition_amount
):
section
,
'pathname'
)),
# add new ones
user
=
user
,
user
=
User
(
"%s%s"
%
(
config
.
user_base_name
,
nb_iter
))
address_list
=
address_list
,
tap
=
tap
,
tap
=
Tap
(
"%s%s"
%
(
config
.
tap_base_name
,
nb_iter
))
))
computer
.
partition_list
=
partition_list
path
=
os
.
path
.
join
(
config
.
instance_root
,
"%s%s"
%
(
config
.
partition_base_name
,
nb_iter
))
computer
.
partition_list
.
append
(
Partition
(
reference
=
"%s%s"
%
(
config
.
partition_base_name
,
nb_iter
),
path
=
path
,
user
=
user
,
address_list
=
None
,
tap
=
tap
,
))
return
computer
def
write_computer_definition
(
config
,
computer
):
computer_definition
=
ConfigParser
.
RawConfigParser
()
computer_definition
.
add_section
(
'computer'
)
if
computer
.
address
is
not
None
and
computer
.
netmask
is
not
None
:
computer_definition
.
set
(
'computer'
,
'address'
,
'/'
.
join
(
[
computer
.
address
,
computer
.
netmask
]))
for
partition_number
,
partition
in
enumerate
(
computer
.
partition_list
):
section
=
'partition_%s'
%
partition_number
computer_definition
.
add_section
(
section
)
address_list
=
[]
for
address
in
partition
.
address_list
:
address_list
.
append
(
'/'
.
join
([
address
[
'addr'
],
address
[
'netmask'
]]))
computer_definition
.
set
(
section
,
'address'
,
' '
.
join
(
address_list
))
computer_definition
.
set
(
section
,
'user'
,
partition
.
user
.
name
)
computer_definition
.
set
(
section
,
'network_interface'
,
partition
.
tap
.
name
)
computer_definition
.
set
(
section
,
'pathname'
,
partition
.
reference
)
computer_definition
.
write
(
open
(
config
.
output_definition_file
,
'w'
))
config
.
logger
.
info
(
'Stored computer definition in %r'
%
config
.
output_definition_file
)
def
run
(
config
):
if
config
.
input_definition_file
:
computer
=
parse_computer_definition
(
config
,
config
.
input_definition_file
)
else
:
else
:
# no definition file, figure out computer
# no definition file, figure out computer
if
os
.
path
.
exists
(
config
.
computer_xml
):
computer
=
parse_computer_xml
(
config
,
config
.
computer_xml
)
config
.
logger
.
info
(
'Loading previous computer data from %r'
%
(
config
.
computer_xml
,
))
computer
=
Computer
.
load
(
config
.
computer_xml
,
reference
=
config
.
computer_id
,
ipv6_interface
=
config
.
ipv6_interface
)
# Connect to the interface defined by the configuration
computer
.
interface
=
Interface
(
config
.
interface_name
,
config
.
ipv4_local_network
,
config
.
ipv6_interface
)
else
:
# If no pre-existent configuration found, creating a new computer object
config
.
logger
.
warning
(
'Creating new data computer with id %r'
%
(
config
.
computer_id
,
))
computer
=
Computer
(
reference
=
config
.
computer_id
,
interface
=
Interface
(
config
.
interface_name
,
config
.
ipv4_local_network
,
config
.
ipv6_interface
),
addr
=
None
,
netmask
=
None
,
ipv6_interface
=
config
.
ipv6_interface
,
software_user
=
config
.
software_user
,
)
partition_amount
=
int
(
config
.
partition_amount
)
existing_partition_amount
=
len
(
computer
.
partition_list
)
if
existing_partition_amount
>
partition_amount
:
raise
ValueError
(
'Requested amount of computer partitions (%s) is lower '
'then already configured (%s), cannot continue'
%
(
partition_amount
,
len
(
computer
.
partition_list
)))
config
.
logger
.
info
(
'Adding %s new partitions'
%
(
partition_amount
-
existing_partition_amount
))
for
nb_iter
in
range
(
existing_partition_amount
,
partition_amount
):
# add new ones
user
=
User
(
"%s%s"
%
(
config
.
user_base_name
,
nb_iter
))
tap
=
Tap
(
"%s%s"
%
(
config
.
tap_base_name
,
nb_iter
))
path
=
os
.
path
.
join
(
config
.
instance_root
,
"%s%s"
%
(
config
.
partition_base_name
,
nb_iter
))
computer
.
partition_list
.
append
(
Partition
(
reference
=
"%s%s"
%
(
config
.
partition_base_name
,
nb_iter
),
path
=
path
,
user
=
user
,
address_list
=
None
,
tap
=
tap
,
))
computer
.
instance_root
=
config
.
instance_root
computer
.
instance_root
=
config
.
instance_root
computer
.
software_root
=
config
.
software_root
computer
.
software_root
=
config
.
software_root
...
@@ -1022,37 +1090,21 @@ def run(config):
...
@@ -1022,37 +1090,21 @@ def run(config):
computer
.
netmask
=
address
[
'netmask'
]
computer
.
netmask
=
address
[
'netmask'
]
if
config
.
output_definition_file
:
if
config
.
output_definition_file
:
computer_definition
=
ConfigParser
.
RawConfigParser
()
write_computer_definition
(
config
,
computer
)
computer_definition
.
add_section
(
'computer'
)
if
computer
.
address
is
not
None
and
computer
.
netmask
is
not
None
:
computer_definition
.
set
(
'computer'
,
'address'
,
'/'
.
join
(
[
computer
.
address
,
computer
.
netmask
]))
partition_number
=
0
for
partition
in
computer
.
partition_list
:
section
=
'partition_%s'
%
partition_number
computer_definition
.
add_section
(
section
)
address_list
=
[]
for
address
in
partition
.
address_list
:
address_list
.
append
(
'/'
.
join
([
address
[
'addr'
],
address
[
'netmask'
]]))
computer_definition
.
set
(
section
,
'address'
,
' '
.
join
(
address_list
))
computer_definition
.
set
(
section
,
'user'
,
partition
.
user
.
name
)
computer_definition
.
set
(
section
,
'user'
,
partition
.
user
.
name
)
computer_definition
.
set
(
section
,
'network_interface'
,
partition
.
tap
.
name
)
computer_definition
.
set
(
section
,
'pathname'
,
partition
.
reference
)
partition_number
+=
1
filepath
=
os
.
path
.
abspath
(
config
.
output_definition_file
)
computer_definition
.
write
(
open
(
filepath
,
'w'
))
config
.
logger
.
info
(
'Stored computer definition in %r'
%
filepath
)
computer
.
construct
(
alter_user
=
config
.
alter_user
,
computer
.
construct
(
alter_user
=
config
.
alter_user
,
alter_network
=
config
.
alter_network
,
create_tap
=
config
.
create_tap
)
alter_network
=
config
.
alter_network
,
create_tap
=
config
.
create_tap
)
# Dumping and sending to the erp5 the current configuration
# Dumping and sending to the erp5 the current configuration
if
not
config
.
dry_run
:
if
not
config
.
dry_run
:
computer
.
dump
(
config
.
computer_xml
)
computer
.
dump
(
path_to_xml
=
config
.
computer_xml
,
path_to_json
=
config
.
computer_json
)
config
.
logger
.
info
(
'Posting information to %r'
%
config
.
master_url
)
config
.
logger
.
info
(
'Posting information to %r'
%
config
.
master_url
)
computer
.
send
(
config
)
computer
.
send
(
config
)
config
.
logger
.
info
(
'slapformat successfully prepared computer.'
)
config
.
logger
.
info
(
'slapformat successfully prepared computer.'
)
class
Config
(
object
):
class
Config
(
object
):
key_file
=
None
key_file
=
None
cert_file
=
None
cert_file
=
None
...
@@ -1060,8 +1112,11 @@ class Config(object):
...
@@ -1060,8 +1112,11 @@ class Config(object):
alter_user
=
None
alter_user
=
None
create_tap
=
None
create_tap
=
None
computer_xml
=
None
computer_xml
=
None
computer_json
=
None
input_definition_file
=
None
logger
=
None
logger
=
None
log_file
=
None
log_file
=
None
output_definition_file
=
None
verbose
=
None
verbose
=
None
dry_run
=
None
dry_run
=
None
console
=
None
console
=
None
...
@@ -1164,6 +1219,7 @@ class Config(object):
...
@@ -1164,6 +1219,7 @@ class Config(object):
self
.
checkRequiredBinary
([[
'tunctl'
,
'-d'
]])
self
.
checkRequiredBinary
([[
'tunctl'
,
'-d'
]])
if
self
.
alter_network
:
if
self
.
alter_network
:
self
.
checkRequiredBinary
([
'ip'
])
self
.
checkRequiredBinary
([
'ip'
])
# Required, even for dry run
# Required, even for dry run
if
self
.
alter_network
and
self
.
create_tap
:
if
self
.
alter_network
and
self
.
create_tap
:
self
.
checkRequiredBinary
([
'brctl'
])
self
.
checkRequiredBinary
([
'brctl'
])
...
@@ -1204,7 +1260,7 @@ class Config(object):
...
@@ -1204,7 +1260,7 @@ class Config(object):
file_location
=
getattr
(
self
,
attribute
,
None
)
file_location
=
getattr
(
self
,
attribute
,
None
)
if
file_location
is
not
None
:
if
file_location
is
not
None
:
if
not
os
.
path
.
exists
(
file_location
):
if
not
os
.
path
.
exists
(
file_location
):
self
.
logger
.
fatal
(
'File %r does not exist or is no readable.'
%
self
.
logger
.
fatal
(
'File %r does not exist or is no
t
readable.'
%
file_location
)
file_location
)
sys
.
exit
(
1
)
sys
.
exit
(
1
)
...
@@ -1220,23 +1276,21 @@ class Config(object):
...
@@ -1220,23 +1276,21 @@ class Config(object):
# Calculate path once
# Calculate path once
self
.
computer_xml
=
os
.
path
.
abspath
(
self
.
computer_xml
)
self
.
computer_xml
=
os
.
path
.
abspath
(
self
.
computer_xml
)
if
self
.
input_definition_file
:
self
.
input_definition_file
=
os
.
path
.
abspath
(
self
.
input_definition_file
)
def
main
(
*
args
):
if
self
.
output_definition_file
:
"Run default configuration."
self
.
output_definition_file
=
os
.
path
.
abspath
(
self
.
output_definition_file
)
def
tracing_monkeypatch
(
config
):
"""Substitute os module and callAndRead function with tracing wrappers."""
global
os
global
os
global
callAndRead
global
callAndRead
real_callAndRead
=
callAndRead
real_callAndRead
=
callAndRead
usage
=
"usage: %s [options] CONFIGURATION_FILE"
%
sys
.
argv
[
0
]
# Parse arguments
options
,
configuration_file_path
=
Parser
(
usage
=
usage
).
check_args
(
args
)
config
=
Config
()
try
:
config
.
setConfig
(
options
,
configuration_file_path
)
except
UsageError
,
err
:
print
>>
sys
.
stderr
,
err
.
message
print
>>
sys
.
stderr
,
"For help use --help"
sys
.
exit
(
1
)
os
=
OS
(
config
)
os
=
OS
(
config
)
if
config
.
dry_run
:
if
config
.
dry_run
:
def
dry_callAndRead
(
argument_list
,
raise_on_error
=
True
):
def
dry_callAndRead
(
argument_list
,
raise_on_error
=
True
):
...
@@ -1253,11 +1307,30 @@ def main(*args):
...
@@ -1253,11 +1307,30 @@ def main(*args):
pwd
.
getpwnam
=
fake_getpwnam
pwd
.
getpwnam
=
fake_getpwnam
else
:
else
:
dry_callAndRead
=
real_callAndRead
dry_callAndRead
=
real_callAndRead
if
config
.
verbose
:
if
config
.
verbose
:
def
logging_callAndRead
(
argument_list
,
raise_on_error
=
True
):
def
logging_callAndRead
(
argument_list
,
raise_on_error
=
True
):
config
.
logger
.
debug
(
' '
.
join
(
argument_list
))
config
.
logger
.
debug
(
' '
.
join
(
argument_list
))
return
dry_callAndRead
(
argument_list
,
raise_on_error
)
return
dry_callAndRead
(
argument_list
,
raise_on_error
)
callAndRead
=
logging_callAndRead
callAndRead
=
logging_callAndRead
def
main
(
*
args
):
"Run default configuration."
# Parse arguments
usage
=
"usage: %s [options] CONFIGURATION_FILE"
%
sys
.
argv
[
0
]
options
,
configuration_file_path
=
Parser
(
usage
=
usage
).
check_args
(
args
)
config
=
Config
()
try
:
config
.
setConfig
(
options
,
configuration_file_path
)
except
UsageError
as
err
:
sys
.
stderr
.
write
(
err
.
message
+
'
\
n
'
)
sys
.
stderr
.
write
(
"For help use --help
\
n
"
)
sys
.
exit
(
1
)
tracing_monkeypatch
(
config
)
# Add delay between 0 and 1 hour
# Add delay between 0 and 1 hour
# XXX should be the contrary: now by default, and cron should have
# XXX should be the contrary: now by default, and cron should have
# --maximal-delay=3600
# --maximal-delay=3600
...
@@ -1271,3 +1344,4 @@ def main(*args):
...
@@ -1271,3 +1344,4 @@ def main(*args):
except
:
except
:
config
.
logger
.
exception
(
'Uncaught exception:'
)
config
.
logger
.
exception
(
'Uncaught exception:'
)
raise
raise
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