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
0
Merge Requests
0
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
Thomas Leymonerie
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):
If configuration file is not given: define it arbitrarily, and so on.
"""
if
is_node_command
:
# XXX-Cedric: should we check if we are root?
if
command
==
'register'
:
call
(
register
)
elif
command
==
'software'
:
...
...
slapos/format.py
View file @
9c0d587c
...
...
@@ -34,6 +34,7 @@ import ConfigParser
import
errno
import
fcntl
import
grp
import
json
import
logging
import
netaddr
import
netifaces
...
...
@@ -50,6 +51,7 @@ import time
import
zipfile
import
lxml.etree
from
slapos.version
import
version
def
prettify_xml
(
xml
):
...
...
@@ -58,6 +60,8 @@ def prettify_xml(xml):
class
OS
(
object
):
"""Wrap parts of the 'os' module to provide logging of performed actions."""
_os
=
os
def
__init__
(
self
,
config
):
...
...
@@ -74,11 +78,9 @@ class OS(object):
def
wrapper
(
*
args
,
**
kw
):
if
self
.
_verbose
:
arg_list
=
[
repr
(
x
)
for
x
in
args
]
+
[
'%s=%r'
%
(
x
,
y
)
for
x
,
y
in
kw
.
iteritems
()]
self
.
_logger
.
debug
(
'%s(%s)'
%
(
name
,
', '
.
join
(
arg_list
)
))
'%s=%r'
%
(
x
,
y
)
for
x
,
y
in
kw
.
iteritems
()
]
self
.
_logger
.
debug
(
'%s(%s)'
%
(
name
,
', '
.
join
(
arg_list
)))
if
not
self
.
_dry_run
:
getattr
(
self
.
_os
,
name
)(
*
args
,
**
kw
)
setattr
(
self
,
name
,
wrapper
)
...
...
@@ -86,12 +88,14 @@ class OS(object):
def
__getattr__
(
self
,
name
):
return
getattr
(
self
.
_os
,
name
)
class
UsageError
(
Exception
):
pass
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.
Attributes:
...
...
@@ -100,9 +104,10 @@ class NoAddressOnInterface(Exception):
def
__init__
(
self
,
interface
):
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
):
"""
Exception raised if the generation of an IPv6 based on the prefix obtained
...
...
@@ -116,31 +121,37 @@ class AddressGenerationError(Exception):
'Generated IPv6 %s seems not to be a valid IP.'
%
addr
)
def
callAndRead
(
argument_list
,
raise_on_error
=
True
):
popen
=
subprocess
.
Popen
(
argument_list
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
popen
=
subprocess
.
Popen
(
argument_list
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
result
=
popen
.
communicate
()[
0
]
if
raise_on_error
and
popen
.
returncode
!=
0
:
raise
ValueError
(
'Issue while invoking %r, result was:
\
n
%s'
%
(
argument_list
,
result
))
argument_list
,
result
))
return
popen
.
returncode
,
result
def
isGlobalScopeAddress
(
a
):
"""Returns True if a is global scope IP v4/6 address"""
ip
=
netaddr
.
IPAddress
(
a
)
return
not
ip
.
is_link_local
()
and
not
ip
.
is_loopback
()
and
\
not
ip
.
is_reserved
()
and
ip
.
is_unicast
()
def
netmaskToPrefixIPv4
(
netmask
):
"""Convert string represented netmask to its integer prefix"""
return
netaddr
.
strategy
.
ipv4
.
netmask_to_prefix
[
netaddr
.
strategy
.
ipv4
.
str_to_int
(
netmask
)]
def
netmaskToPrefixIPv6
(
netmask
):
"""Convert string represented netmask to its integer prefix"""
return
netaddr
.
strategy
.
ipv6
.
netmask_to_prefix
[
netaddr
.
strategy
.
ipv6
.
str_to_int
(
netmask
)]
def
_getDict
(
instance
):
"""
Serialize an object instance into dictionaries. List and dict will remains
...
...
@@ -172,13 +183,14 @@ def _getDict(instance):
result
[
key
]
=
_getDict
(
value
)
return
result
class
Computer
(
object
):
"Object representing the computer"
instance_root
=
None
software_root
=
None
def
__init__
(
self
,
reference
,
interface
=
None
,
addr
=
None
,
netmask
=
None
,
ipv6_interface
=
None
,
software_user
=
'slapsoft'
):
ipv6_interface
=
None
,
software_user
=
'slapsoft'
):
"""
Attributes:
reference: String, the reference of the computer.
...
...
@@ -197,14 +209,14 @@ class Computer(object):
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).
Returns:
False if the interface isn't available, else the list of the free addresses.
"""
if
self
.
interface
is
None
:
return
dict
(
addr
=
self
.
address
,
netmask
=
self
.
netmask
)
return
{
'addr'
:
self
.
address
,
'netmask'
:
self
.
netmask
}
computer_partition_address_list
=
[]
for
partition
in
self
.
partition_list
:
...
...
@@ -218,15 +230,14 @@ class Computer(object):
return
address_dict
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
.
createWithOwner
(
User
(
'root'
),
attach_to_tap
=
True
)
self
.
interface
.
addTap
(
computer_tap
)
return
self
.
interface
.
addAddr
()
# Can't find address
raise
NoAddressOnInterface
(
'No valid IPv6 found on %s.'
%
self
.
interface
.
name
)
raise
NoAddressOnInterface
(
'No valid IPv6 found on %s.'
%
self
.
interface
.
name
)
def
send
(
self
,
config
):
"""
...
...
@@ -236,12 +247,12 @@ class Computer(object):
slap_instance
=
slap
.
slap
()
connection_dict
=
{}
if
config
.
key_file
and
config
.
cert_file
:
connection_dict
.
update
(
key_file
=
config
.
key_file
,
cert_file
=
config
.
cert_file
)
connection_dict
[
'key_file'
]
=
config
.
key_file
connection_dict
[
'cert_file'
]
=
config
.
cert_file
slap_instance
.
initializeConnection
(
config
.
master_url
,
**
connection_dict
)
**
connection_dict
)
slap_computer
=
slap_instance
.
registerComputer
(
self
.
reference
)
if
config
.
dry_run
:
return
try
:
...
...
@@ -250,19 +261,22 @@ class Computer(object):
raise
slap
.
NotFoundError
(
"%s
\
n
ERROR : This SlapOS node is not recognised by "
"SlapOS Master. Please make sure computer_id of slapos.cfg looks "
"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.
Args:
path_to_xml: String, path to the file to load.
users: List of User, list of user needed to be add to the dump
(even if they are not related to any tap interface).
path_to_json: String, path to the JSON version to save.
"""
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_pretty_xml
=
prettify_xml
(
new_xml
)
...
...
@@ -275,13 +289,17 @@ class Computer(object):
# computer configuration did not change, nothing to write
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
:
fout
.
write
(
new_pretty_xml
)
with
open
(
path_to_xml
,
'wb'
)
as
fout
:
fout
.
write
(
new_pretty_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
()
saved_filename
=
os
.
path
.
basename
(
path_to_xml
)
+
time
.
strftime
(
'.%Y%m%d-%H:%M'
)
...
...
@@ -309,8 +327,8 @@ class Computer(object):
reference
=
reference
,
addr
=
dumped_dict
[
'address'
],
netmask
=
dumped_dict
[
'netmask'
],
ipv6_interface
=
ipv6_interface
,
software_user
=
dumped_dict
.
get
(
'software_user'
,
'slapsoft'
),
ipv6_interface
=
ipv6_interface
,
software_user
=
dumped_dict
.
get
(
'software_user'
,
'slapsoft'
),
)
for
partition_dict
in
dumped_dict
[
'partition_list'
]:
...
...
@@ -411,6 +429,7 @@ class Computer(object):
if
not
any
([
netaddr
.
valid_ipv4
(
q
[
'addr'
])
for
q
in
old_partition_address_list
]):
raise
ValueError
(
'Not valid ipv6 addresses loaded'
)
for
address
in
old_partition_address_list
:
if
netaddr
.
valid_ipv6
(
address
[
'addr'
]):
partition
.
address_list
.
append
(
self
.
interface
.
addAddr
(
...
...
@@ -428,6 +447,7 @@ class Computer(object):
except
IndexError
:
pass
class
Partition
(
object
):
"Represent a computer partition"
...
...
@@ -465,8 +485,10 @@ class Partition(object):
os
.
chown
(
self
.
path
,
owner_pw
.
pw_uid
,
owner_pw
.
pw_gid
)
os
.
chmod
(
self
.
path
,
0750
)
class
User
(
object
):
"User: represent and manipulate a user on the system."
"""User: represent and manipulate a user on the system."""
path
=
None
def
__init__
(
self
,
user_name
,
additional_group_list
=
None
):
...
...
@@ -526,7 +548,6 @@ class User(object):
try
:
pwd
.
getpwnam
(
self
.
name
)
return
True
except
KeyError
:
return
False
...
...
@@ -551,7 +572,7 @@ class Tap(object):
def
attach
(
self
):
"""
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
interface. The former can be set manually by running ``ip link set dev
...
...
@@ -579,7 +600,7 @@ class Tap(object):
fcntl
.
ioctl
(
tap_fd
,
self
.
TUNSETIFF
,
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
# ignore it...
if
error
.
errno
!=
errno
.
EBUSY
:
...
...
@@ -622,8 +643,9 @@ class Tap(object):
if
attach_to_tap
:
threading
.
Thread
(
target
=
self
.
attach
).
start
()
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
):
"""
...
...
@@ -640,6 +662,9 @@ class Interface(object):
_
,
result
=
callAndRead
([
'ip'
,
'addr'
,
'list'
,
self
.
name
])
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
):
return
(
self
.
name
,)
...
...
@@ -735,7 +760,8 @@ class Interface(object):
if
not
af
in
netifaces
.
ifaddresses
(
interface_name
)
\
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
callAndRead
([
'ip'
,
'addr'
,
'add'
,
address_string
,
'dev'
,
interface_name
])
...
...
@@ -745,14 +771,18 @@ class Interface(object):
# wait few moments
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
])
for
l
in
result
.
split
(
'
\
n
'
):
if
address
in
l
:
if
'tentative'
in
l
:
# duplicate, remove
callAndRead
([
'ip'
,
'addr'
,
'del'
,
address_string
,
'dev'
,
interface_name
])
callAndRead
([
'ip'
,
'addr'
,
'del'
,
address_string
,
'dev'
,
interface_name
])
return
False
# found and clean
return
True
...
...
@@ -785,6 +815,8 @@ class Interface(object):
if
self
.
_addSystemAddress
(
addr
,
netmask
,
False
):
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
else
:
self
.
logger
.
warning
(
'Impossible to add old local IPv4 %s. Generating '
'new IPv4 address.'
%
addr
)
return
self
.
_generateRandomIPv4Address
(
netmask
)
else
:
# confirmed to be configured
...
...
@@ -840,6 +872,9 @@ class Interface(object):
if
self
.
_addSystemAddress
(
addr
,
netmask
):
# succeed, return it
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_num
=
10
...
...
@@ -857,11 +892,12 @@ class Interface(object):
raise
AddressGenerationError
(
addr
)
class
Parser
(
OptionParser
):
"""
Parse all arguments.
"""
def
__init__
(
self
,
usage
=
None
,
version
=
None
):
def
__init__
(
self
,
usage
=
None
,
version
=
version
):
"""
Initialize all options possibles.
"""
...
...
@@ -872,6 +908,10 @@ class Parser(OptionParser):
"will be created"
,
default
=
None
,
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"
,
help
=
"The path to the log file used by the script."
,
type
=
str
),
...
...
@@ -919,100 +959,128 @@ class Parser(OptionParser):
self
.
error
(
"Incorrect number of arguments"
)
return
options
,
args
[
0
]
def
run
(
config
):
# Define the computer
if
config
.
input_definition_file
:
filepath
=
os
.
path
.
abspath
(
config
.
input_definition_file
)
config
.
logger
.
info
(
'Using definition file %r'
%
filepath
)
computer_definition
=
ConfigParser
.
RawConfigParser
({
'software_user'
:
'slapsoft'
,
})
computer_definition
.
read
(
filepath
)
interface
=
None
address
=
None
netmask
=
None
if
computer_definition
.
has_option
(
'computer'
,
'address'
):
address
,
netmask
=
computer_definition
.
get
(
'computer'
,
'address'
).
split
(
'/'
)
if
config
.
alter_network
and
config
.
interface_name
is
not
None
\
and
config
.
ipv4_local_network
is
not
None
:
interface
=
Interface
(
config
.
interface_name
,
config
.
ipv4_local_network
,
def
parse_computer_definition
(
config
,
definition_path
):
config
.
logger
.
info
(
'Using definition file %r'
%
definition_path
)
computer_definition
=
ConfigParser
.
RawConfigParser
({
'software_user'
:
'slapsoft'
,
})
computer_definition
.
read
(
definition_path
)
interface
=
None
address
=
None
netmask
=
None
if
computer_definition
.
has_option
(
'computer'
,
'address'
):
address
,
netmask
=
computer_definition
.
get
(
'computer'
,
'address'
).
split
(
'/'
)
if
config
.
alter_network
and
config
.
interface_name
is
not
None
\
and
config
.
ipv4_local_network
is
not
None
:
interface
=
Interface
(
config
.
interface_name
,
config
.
ipv4_local_network
,
config
.
ipv6_interface
)
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
)
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
(
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_list
.
append
(
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
,
))
computer
.
partition_list
=
partition_list
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
,
))
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
:
# no definition file, figure out computer
if
os
.
path
.
exists
(
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
=
parse_computer_xml
(
config
,
config
.
computer_xml
)
computer
.
instance_root
=
config
.
instance_root
computer
.
software_root
=
config
.
software_root
...
...
@@ -1022,37 +1090,21 @@ def run(config):
computer
.
netmask
=
address
[
'netmask'
]
if
config
.
output_definition_file
:
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
]))
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
)
write_computer_definition
(
config
,
computer
)
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
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
)
computer
.
send
(
config
)
config
.
logger
.
info
(
'slapformat successfully prepared computer.'
)
class
Config
(
object
):
key_file
=
None
cert_file
=
None
...
...
@@ -1060,8 +1112,11 @@ class Config(object):
alter_user
=
None
create_tap
=
None
computer_xml
=
None
computer_json
=
None
input_definition_file
=
None
logger
=
None
log_file
=
None
output_definition_file
=
None
verbose
=
None
dry_run
=
None
console
=
None
...
...
@@ -1164,6 +1219,7 @@ class Config(object):
self
.
checkRequiredBinary
([[
'tunctl'
,
'-d'
]])
if
self
.
alter_network
:
self
.
checkRequiredBinary
([
'ip'
])
# Required, even for dry run
if
self
.
alter_network
and
self
.
create_tap
:
self
.
checkRequiredBinary
([
'brctl'
])
...
...
@@ -1204,7 +1260,7 @@ class Config(object):
file_location
=
getattr
(
self
,
attribute
,
None
)
if
file_location
is
not
None
:
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
)
sys
.
exit
(
1
)
...
...
@@ -1220,23 +1276,21 @@ class Config(object):
# Calculate path once
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
):
"Run default configuration."
if
self
.
output_definition_file
:
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
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
)
if
config
.
dry_run
:
def
dry_callAndRead
(
argument_list
,
raise_on_error
=
True
):
...
...
@@ -1253,11 +1307,30 @@ def main(*args):
pwd
.
getpwnam
=
fake_getpwnam
else
:
dry_callAndRead
=
real_callAndRead
if
config
.
verbose
:
def
logging_callAndRead
(
argument_list
,
raise_on_error
=
True
):
config
.
logger
.
debug
(
' '
.
join
(
argument_list
))
return
dry_callAndRead
(
argument_list
,
raise_on_error
)
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
# XXX should be the contrary: now by default, and cron should have
# --maximal-delay=3600
...
...
@@ -1271,3 +1344,4 @@ def main(*args):
except
:
config
.
logger
.
exception
(
'Uncaught exception:'
)
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