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
Léo-Paul Géneau
slapos.core
Commits
5fbb22ab
Commit
5fbb22ab
authored
Apr 18, 2013
by
Marco Mariani
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cli refactoring: node format
parent
d0b40e71
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
198 additions
and
136 deletions
+198
-136
setup.py
setup.py
+1
-0
slapos/cli/format.py
slapos/cli/format.py
+76
-0
slapos/format.py
slapos/format.py
+121
-136
No files found.
setup.py
View file @
5fbb22ab
...
...
@@ -75,6 +75,7 @@ setup(name=name,
'slapos.cli'
:
[
'cache lookup = slapos.cli.cache:CacheLookupCommand'
,
'node bang = slapos.cli.bang:BangCommand'
,
'node format = slapos.cli.format:FormatCommand'
,
]
},
test_suite
=
"slapos.tests"
,
...
...
slapos/cli/format.py
0 → 100644
View file @
5fbb22ab
# -*- coding: utf-8 -*-
import
logging
import
sys
from
slapos.cli.config
import
ConfigCommand
from
slapos.format
import
do_format
,
FormatConfig
,
tracing_monkeypatch
,
UsageError
class
FormatCommand
(
ConfigCommand
):
log
=
logging
.
getLogger
(
'slapformat'
)
def
get_parser
(
self
,
prog_name
):
ap
=
super
(
FormatCommand
,
self
).
get_parser
(
prog_name
)
ap
.
add_argument
(
'-x'
,
'--computer_xml'
,
help
=
"Path to file with computer's XML. If does not exists, will be created"
,
default
=
None
)
ap
.
add_argument
(
'--computer_json'
,
help
=
"Path to a JSON version of the computer's XML (for development only)."
,
default
=
None
)
ap
.
add_argument
(
'-l'
,
'--log_file'
,
help
=
"The path to the log file used by the script."
)
ap
.
add_argument
(
'-i'
,
'--input_definition_file'
,
help
=
"Path to file to read definition of computer instead of "
"declaration. Using definition file allows to disable "
"'discovery' of machine services and allows to define computer "
"configuration in fully controlled manner."
)
ap
.
add_argument
(
'-o'
,
'--output_definition_file'
,
help
=
"Path to file to write definition of computer from "
"declaration."
)
ap
.
add_argument
(
'-n'
,
'--dry_run'
,
help
=
"Don't actually do anything."
,
default
=
False
,
action
=
"store_true"
)
ap
.
add_argument
(
'--alter_user'
,
choices
=
[
'True'
,
'False'
],
help
=
"Shall slapformat alter user database [default: True]"
)
ap
.
add_argument
(
'--alter_network'
,
choices
=
[
'True'
,
'False'
],
help
=
"Shall slapformat alter network configuration [default: True]"
)
ap
.
add_argument
(
'--now'
,
help
=
"Launch slapformat without delay"
,
default
=
False
,
action
=
"store_true"
)
return
ap
def
take_action
(
self
,
args
):
configuration_parser
=
self
.
fetch_config
(
args
)
config
=
FormatConfig
(
logger
=
self
.
log
)
try
:
config
.
setConfig
(
args
,
configuration_parser
)
except
UsageError
as
err
:
sys
.
stderr
.
write
(
err
.
message
+
'
\
n
'
)
sys
.
stderr
.
write
(
"For help use --help
\
n
"
)
sys
.
exit
(
1
)
tracing_monkeypatch
(
config
)
try
:
do_format
(
config
=
config
)
except
:
self
.
log
.
exception
(
'Uncaught exception:'
)
raise
slapos/format.py
View file @
5fbb22ab
...
...
@@ -28,8 +28,7 @@
#
##############################################################################
from
optparse
import
OptionParser
,
Option
from
xml_marshaller
import
xml_marshaller
import
argparse
import
ConfigParser
import
errno
import
fcntl
...
...
@@ -41,7 +40,6 @@ import netifaces
import
os
import
pwd
import
random
import
slapos.slap
as
slap
import
socket
import
struct
import
subprocess
...
...
@@ -51,12 +49,10 @@ import time
import
zipfile
import
lxml.etree
from
slapos.version
import
version
import
xml_marshaller.xml_marshaller
# set up logging
logger
=
logging
.
getLogger
(
"slapformat"
)
logger
.
setLevel
(
logging
.
INFO
)
from
slapos.util
import
mkdir_p
import
slapos.slap
as
slap
def
prettify_xml
(
xml
):
...
...
@@ -64,8 +60,6 @@ def prettify_xml(xml):
return
lxml
.
etree
.
tostring
(
root
,
pretty_print
=
True
)
from
slapos.util
import
mkdir_p
class
OS
(
object
):
"""Wrap parts of the 'os' module to provide logging of performed actions."""
...
...
@@ -73,7 +67,6 @@ class OS(object):
def
__init__
(
self
,
config
):
self
.
_dry_run
=
config
.
dry_run
self
.
_verbose
=
config
.
verbose
self
.
_logger
=
config
.
logger
add
=
self
.
_addWrapper
add
(
'chown'
)
...
...
@@ -83,7 +76,6 @@ class OS(object):
def
_addWrapper
(
self
,
name
):
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
()
]
...
...
@@ -263,7 +255,7 @@ class Computer(object):
if
config
.
dry_run
:
return
try
:
slap_computer
.
updateConfiguration
(
xml_marshaller
.
dumps
(
_getDict
(
self
)))
slap_computer
.
updateConfiguration
(
xml_marshaller
.
xml_marshaller
.
dumps
(
_getDict
(
self
)))
except
slap
.
NotFoundError
as
error
:
raise
slap
.
NotFoundError
(
"%s
\
n
ERROR : This SlapOS node is not recognised by "
"SlapOS Master. Please make sure computer_id of slapos.cfg looks "
...
...
@@ -284,7 +276,7 @@ class Computer(object):
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
.
xml_marshaller
.
dumps
(
computer_dict
)
new_pretty_xml
=
prettify_xml
(
new_xml
)
path_to_archive
=
path_to_xml
+
'.zip'
...
...
@@ -327,7 +319,7 @@ class Computer(object):
A Computer object.
"""
dumped_dict
=
xml_marshaller
.
loads
(
open
(
path_to_xml
).
read
())
dumped_dict
=
xml_marshaller
.
xml_marshaller
.
loads
(
open
(
path_to_xml
).
read
())
# Reconstructing the computer object from the xml
computer
=
Computer
(
...
...
@@ -671,12 +663,13 @@ class Tap(object):
class
Interface
(
object
):
"""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
,
logger
=
None
):
"""
Attributes:
name: String, the name of the interface
"""
self
.
logger
=
logger
self
.
name
=
str
(
name
)
self
.
ipv4_local_network
=
ipv4_local_network
self
.
ipv6_interface
=
ipv6_interface
...
...
@@ -840,7 +833,7 @@ class Interface(object):
if
self
.
_addSystemAddress
(
addr
,
netmask
,
False
):
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
else
:
logger
.
warning
(
'Impossible to add old local IPv4 %s. Generating '
self
.
logger
.
warning
(
'Impossible to add old local IPv4 %s. Generating '
'new IPv4 address.'
%
addr
)
return
self
.
_generateRandomIPv4Address
(
netmask
)
else
:
...
...
@@ -898,7 +891,7 @@ class Interface(object):
# succeed, return it
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
else
:
logger
.
warning
(
'Impossible to add old public IPv6 %s. '
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
...
...
@@ -918,74 +911,6 @@ class Interface(object):
raise
AddressGenerationError
(
addr
)
class
Parser
(
OptionParser
):
"""
Parse all arguments.
"""
def
__init__
(
self
,
usage
=
None
,
version
=
version
):
"""
Initialize all options possibles.
"""
OptionParser
.
__init__
(
self
,
usage
=
usage
,
version
=
version
,
option_list
=
[
Option
(
"-x"
,
"--computer_xml"
,
help
=
"Path to file with computer's XML. If does not exists, "
"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
),
Option
(
"-i"
,
"--input_definition_file"
,
help
=
"Path to file to read definition of computer instead of "
"declaration. Using definition file allows to disable "
"'discovery' of machine services and allows to define computer "
"configuration in fully controlled manner."
,
type
=
str
),
Option
(
"-o"
,
"--output_definition_file"
,
help
=
"Path to file to write definition of computer from "
"declaration."
,
type
=
str
),
Option
(
"-n"
,
"--dry_run"
,
help
=
"Don't actually do anything."
,
default
=
False
,
action
=
"store_true"
),
Option
(
"-v"
,
"--verbose"
,
default
=
False
,
action
=
"store_true"
,
help
=
"Verbose output."
),
Option
(
"-c"
,
"--console"
,
default
=
False
,
action
=
"store_true"
,
help
=
"Console output."
),
Option
(
'--alter_user'
,
choices
=
[
'True'
,
'False'
],
help
=
"Shall slapformat alter user database [default: True]"
),
Option
(
'--alter_network'
,
choices
=
[
'True'
,
'False'
],
help
=
"Shall slapformat alter network configuration [default: True]"
),
Option
(
'--now'
,
help
=
"Launch slapformat without delay"
,
default
=
False
,
action
=
"store_true"
),
])
def
check_args
(
self
,
args
):
"""
Check arguments
"""
if
args
:
(
options
,
args
)
=
self
.
parse_args
(
list
(
args
))
else
:
(
options
,
args
)
=
self
.
parse_args
()
if
len
(
args
)
!=
1
:
self
.
error
(
"Incorrect number of arguments"
)
return
options
,
args
[
0
]
def
parse_computer_definition
(
config
,
definition_path
):
config
.
logger
.
info
(
'Using definition file %r'
%
definition_path
)
computer_definition
=
ConfigParser
.
RawConfigParser
({
...
...
@@ -1000,7 +925,7 @@ def parse_computer_definition(config, definition_path):
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
)
config
.
ipv6_interface
,
logger
=
config
.
logger
)
computer
=
Computer
(
reference
=
config
.
computer_id
,
interface
=
interface
,
...
...
@@ -1059,7 +984,7 @@ def parse_computer_xml(config, xml_path):
len
(
computer
.
partition_list
)))
config
.
logger
.
info
(
'Adding %s new partitions'
%
(
partition_amount
-
existing_partition_amount
))
(
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
))
...
...
@@ -1100,7 +1025,20 @@ def write_computer_definition(config, computer):
config
.
logger
.
info
(
'Stored computer definition in %r'
%
config
.
output_definition_file
)
def
run
(
config
):
def
random_delay
(
config
):
# Add delay between 0 and 1 hour
# XXX should be the contrary: now by default, and cron should have
# --maximal-delay=3600
if
not
config
.
now
:
duration
=
float
(
60
*
60
)
*
random
.
random
()
print
(
"Sleeping for %s seconds. To disable this feature, "
\
"use with --now parameter in manual."
%
duration
)
time
.
sleep
(
duration
)
def
do_format
(
config
):
random_delay
(
config
)
if
config
.
input_definition_file
:
computer
=
parse_computer_definition
(
config
,
config
.
input_definition_file
)
else
:
...
...
@@ -1133,7 +1071,7 @@ def run(config):
config
.
logger
.
info
(
'slapformat successfully prepared computer.'
)
class
Config
(
object
):
class
Format
Config
(
object
):
key_file
=
None
cert_file
=
None
alter_network
=
None
...
...
@@ -1142,14 +1080,14 @@ class Config(object):
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
software_user
=
None
def
__init__
(
self
,
logger
):
self
.
logger
=
logger
@
staticmethod
def
checkRequiredBinary
(
binary_list
):
missing_binary_list
=
[]
...
...
@@ -1166,26 +1104,17 @@ class Config(object):
raise
UsageError
(
'Some required binaries are missing or not '
'functional: %s'
%
(
','
.
join
(
missing_binary_list
),
))
def
setConfig
(
self
,
option
_dict
,
configuration_file_path
):
def
setConfig
(
self
,
option
s
,
configuration_parser
):
"""
Set options given by parameters.
"""
self
.
key_file
=
None
self
.
cert_file
=
None
# set up logging
# XXX-Cedric: change code to use global logger
self
.
logger
=
logger
# Set options parameters
for
option
,
value
in
option
_dict
.
__dict__
.
items
():
for
option
,
value
in
option
s
.
__dict__
.
items
():
setattr
(
self
,
option
,
value
)
# Load configuration file
configuration_parser
=
ConfigParser
.
SafeConfigParser
()
if
configuration_parser
.
read
(
configuration_file_path
)
!=
[
configuration_file_path
]:
raise
UsageError
(
'Cannot find or parse configuration file: %s'
%
configuration_file_path
)
# Merges the arguments and configuration
for
section
in
(
"slapformat"
,
"slapos"
):
configuration_dict
=
dict
(
configuration_parser
.
items
(
section
))
...
...
@@ -1221,10 +1150,6 @@ class Config(object):
if
self
.
create_tap
is
None
:
self
.
create_tap
=
True
# Configure logging
if
self
.
console
:
self
.
logger
.
addHandler
(
logging
.
StreamHandler
())
# Convert strings to booleans
for
o
in
[
'alter_network'
,
'alter_user'
,
'create_tap'
]:
attr
=
getattr
(
self
,
o
)
...
...
@@ -1262,7 +1187,7 @@ class Config(object):
if
root_needed
and
os
.
getuid
()
!=
0
:
message
=
"Root rights are needed"
self
.
logger
.
error
(
message
)
sys
.
stderr
.
write
(
message
+
'
\
n
'
)
sys
.
stderr
.
write
(
message
+
'
\
n
'
)
sys
.
exit
()
if
self
.
log_file
:
...
...
@@ -1294,9 +1219,6 @@ class Config(object):
sys
.
exit
(
1
)
self
.
logger
.
info
(
"Started."
)
if
self
.
verbose
:
self
.
logger
.
setLevel
(
logging
.
DEBUG
)
self
.
logger
.
debug
(
"Verbose mode enabled."
)
if
self
.
dry_run
:
self
.
logger
.
info
(
"Dry-run mode enabled."
)
if
self
.
create_tap
:
...
...
@@ -1312,7 +1234,6 @@ class Config(object):
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
...
...
@@ -1328,6 +1249,7 @@ def tracing_monkeypatch(config):
else
:
return
0
,
''
callAndRead
=
dry_callAndRead
def
fake_getpwnam
(
user
):
class
result
(
object
):
pw_uid
=
12345
...
...
@@ -1337,7 +1259,6 @@ def tracing_monkeypatch(config):
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
)
...
...
@@ -1348,11 +1269,84 @@ 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
()
ap
=
argparse
.
ArgumentParser
(
usage
=
'usage: %s [options] CONFIGURATION_FILE'
%
sys
.
argv
[
0
])
ap
.
add_argument
(
'-x'
,
'--computer_xml'
,
help
=
"Path to file with computer's XML. If does not exists, will be created"
,
default
=
None
)
ap
.
add_argument
(
'--computer_json'
,
help
=
"Path to a JSON version of the computer's XML (for development only)."
,
default
=
None
)
ap
.
add_argument
(
'-l'
,
'--log_file'
,
help
=
"The path to the log file used by the script."
)
ap
.
add_argument
(
'-i'
,
'--input_definition_file'
,
help
=
"Path to file to read definition of computer instead of "
"declaration. Using definition file allows to disable "
"'discovery' of machine services and allows to define computer "
"configuration in fully controlled manner."
)
ap
.
add_argument
(
'-o'
,
'--output_definition_file'
,
help
=
"Path to file to write definition of computer from "
"declaration."
)
ap
.
add_argument
(
'-n'
,
'--dry_run'
,
help
=
"Don't actually do anything."
,
default
=
False
,
action
=
"store_true"
)
ap
.
add_argument
(
'-v'
,
'--verbose'
,
default
=
False
,
action
=
"store_true"
,
help
=
"Verbose output."
)
# the console option is actually ignored and not used anymore.
ap
.
add_argument
(
'-c'
,
'--console'
,
default
=
False
,
action
=
"store_true"
,
help
=
"Console output."
)
ap
.
add_argument
(
'--alter_user'
,
choices
=
[
'True'
,
'False'
],
help
=
"Shall slapformat alter user database [default: True]"
)
ap
.
add_argument
(
'--alter_network'
,
choices
=
[
'True'
,
'False'
],
help
=
"Shall slapformat alter network configuration [default: True]"
)
ap
.
add_argument
(
'--now'
,
help
=
"Launch slapformat without delay"
,
default
=
False
,
action
=
"store_true"
)
ap
.
add_argument
(
'configuration_file'
,
help
=
'path to slapos.cfg'
)
if
args
:
options
=
ap
.
parse_args
(
list
(
args
))
else
:
options
=
ap
.
parse_args
()
logger
=
logging
.
getLogger
(
"slapformat"
)
logger
.
addHandler
(
logging
.
StreamHandler
())
if
options
.
verbose
:
logger
.
setLevel
(
logging
.
DEBUG
)
logger
.
debug
(
"Verbose mode enabled."
)
else
:
logger
.
setLevel
(
logging
.
INFO
)
config
=
FormatConfig
(
logger
=
logger
)
configuration_parser
=
ConfigParser
.
SafeConfigParser
()
if
configuration_parser
.
read
(
options
.
configuration_file
)
!=
[
options
.
configuration_file
]:
raise
UsageError
(
'Cannot find or parse configuration file: %s'
%
options
.
configuration_file
)
try
:
config
.
setConfig
(
options
,
configuration_
file_path
)
config
.
setConfig
(
options
,
configuration_
parser
)
except
UsageError
as
err
:
sys
.
stderr
.
write
(
err
.
message
+
'
\
n
'
)
sys
.
stderr
.
write
(
"For help use --help
\
n
"
)
...
...
@@ -1360,17 +1354,8 @@ def main(*args):
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
if
not
config
.
now
:
duration
=
float
(
60
*
60
)
*
random
.
random
()
print
(
"Sleeping for %s seconds. To disable this feature, "
\
"use with --now parameter in manual."
%
duration
)
time
.
sleep
(
duration
)
try
:
run
(
config
)
do_format
(
config
=
config
)
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