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
Labels
Merge Requests
17
Merge Requests
17
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
nexedi
slapos.core
Commits
d393206c
Commit
d393206c
authored
Jun 02, 2017
by
Tomáš Peterka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Extract cgroup-cpuset functionality into 'plugin-like' Manager class
parent
2a14a5c8
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
352 additions
and
150 deletions
+352
-150
slapos/format.py
slapos/format.py
+182
-68
slapos/tests/slapformat.py
slapos/tests/slapformat.py
+170
-82
No files found.
slapos/format.py
View file @
d393206c
...
@@ -237,35 +237,193 @@ def _getDict(obj):
...
@@ -237,35 +237,193 @@ def _getDict(obj):
}
}
class
CGroupManager
(
object
):
"""Manage cgroups in terms on initializing and runtime operations.
This class takes advantage of slapformat being run periodically thus
it can act as a "daemon" performing runtime tasks.
"""
cpu_exclusive_file
=
".slapos-cpu-exclusive"
cpuset_path
=
"/sys/fs/cgroup/cpuset/"
def
__init__
(
self
,
computer
):
"""Extract necessary information from the ``computer``.
:param computer: slapos.format.Computer, extract necessary attributes
"""
self
.
instance_root
=
computer
.
instance_root
self
.
software_gid
=
computer
.
software_gid
def
allowed
(
self
):
return
os
.
path
.
exists
(
"/sys/fs/cgroup/cpuset/cpuset.cpus"
):
def
format
(
self
):
"""Build CGROUP tree to fit SlapOS needs.
- Create hierarchy of CPU sets so that every partition can have exclusive
hold of one of the CPUs.
"""
self
.
prepare_cpuset
()
self
.
prepare_cpu_space
()
def
update
(
self
):
"""Control runtime state of the computer."""
self
.
prepare_cpu_space
()
self
.
ensure_exlusive_cpu
()
def
prepare_cpuset
(
self
):
"""Create cgroup folder per-CPU with exclusive access to the CPU.
Those folders are "/sys/fs/cgroup/cpuset/cpu<N>".
"""
for
cpu
in
self
.
_list_cpus
():
cpu_path
=
self
.
_prepare_cgroup_folder
(
os
.
path
.
join
(
self
.
cpuset_path
,
"cpu"
+
str
(
cpu
)))
with
open
(
cpu_path
+
"/cpuset.cpus"
,
"wt"
)
as
fx
:
fx
.
write
(
str
(
cpu
))
# this cgroup manages only this cpu
with
open
(
cpu_path
+
"/cpuset.cpu_exclusive"
,
"wt"
)
as
fx
:
fx
.
write
(
"1"
)
# manages it exclusively
with
open
(
cpu_path
+
"/cpuset.mems"
,
"wt"
)
as
fx
:
fx
.
write
(
"0"
)
# it doesn't work without that
os
.
chown
(
cpu_path
+
"/tasks"
,
-
1
,
self
.
software_gid
)
os
.
chmod
(
cpu_path
+
"/tasks"
,
0o664
)
def
ensure_exlusive_cpu
(
self
):
"""Move processes among exclusive CPUSets based on software release demands.
We expect PIDs which require own CPU to be found in ~instance/.slapos-cpu-exclusive
"""
request_pid_set
=
set
()
# gather requests from all instances
for
request_file
in
glob
.
iglob
(
os
.
path
.
join
(
self
.
instance_root
,
'*'
,
CGroupManager
.
cpu_exclusive_file
)):
with
open
(
request_file
,
"rt"
)
as
fi
:
request_pid_set
.
update
(
map
(
int
,
fi
.
read
().
split
()))
cpu_list
=
self
.
_list_cpus
()
generic_cpu
=
cpu_list
[
0
]
exclusive_cpu_list
=
cpu_list
[
1
:]
# gather all running PIDs for filtering out stale PIDs
running_pid_set
=
set
()
with
open
(
os
.
path
.
join
(
self
.
cpuset_path
,
"tasks"
),
"rt"
)
as
fi
:
running_pid_set
.
update
(
map
(
int
,
fi
.
read
().
split
()))
with
open
(
os
.
path
.
join
(
self
.
cpuset_path
,
"cpu"
+
str
(
generic_cpu
),
"tasks"
),
"rt"
)
as
fi
:
running_pid_set
.
update
(
map
(
int
,
fi
.
read
().
split
()))
# gather already exclusively running PIDs
exlusive_pid_set
=
set
()
for
exclusive_cpu
in
exclusive_cpu_list
:
with
open
(
os
.
path
.
join
(
self
.
cpuset_path
,
"cpu"
+
str
(
exclusive_cpu
),
"tasks"
),
"rt"
)
as
fi
:
exlusive_pid_set
.
update
(
map
(
int
,
fi
.
read
().
split
()))
for
request
in
request_set
:
if
request
in
exclusive_pid_set
:
continue
# already exclusive
if
request
not
in
running_pid_set
:
continue
# stale PID which is not running anywhere
self
.
_move_to_exclusive_cpu
(
request
)
def
prepare_cpu_space
(
self
):
"""Move all PIDs from the pool of all CPUs into the first exclusive CPU."""
with
open
(
self
.
cpuset_path
+
"tasks"
,
"rt"
)
as
fi
:
running_set
=
set
(
map
(
int
,
fi
.
read
().
split
()))
first_cpu
=
self
.
_list_cpus
()[
0
]
task_path
=
os
.
path
.
join
(
self
.
cpuset_path
,
"cpu"
+
str
(
first_cpu
),
"tasks"
)
for
pid
in
running_set
:
with
open
(
task_path
,
"wt"
)
as
fo
:
fo
.
write
(
str
(
pid
))
time
.
sleep
(
0.01
)
def
_list_cpus
(
self
):
"""Extract IDs of available CPUs and return them as a list.
The first one will be always used for all non-exclusive processes.
:return: list[int]
"""
cpu_list
=
[]
# types: list[int]
with
open
(
self
.
cpuset_path
+
"cpuset.cpus"
,
"rt"
)
as
cpu_def
:
for
cpu_def_split
in
cpu_def
.
read
().
strip
().
split
(
","
):
# IDs can be in form "0-4" or "0,1,2,3,4"
if
"-"
in
cpu_def_split
:
a
,
b
=
map
(
int
,
cpu_def_split
.
split
(
"-"
))
cpu_list
.
extend
(
range
(
a
,
b
+
1
))
# because cgroup's range is inclusive
continue
cpu_list
.
append
(
int
(
cpu_def_split
))
return
cpu_list
def
_move_to_exclusive_cpu
(
self
,
pid
):
"""Try all exclusive CPUs and place the ``pid`` to the first available one.
:return: int, cpu_id of used CPU, -1 if placement was not possible
"""
exclusive_cpu_list
=
self
.
_list_cpus
()[
1
:]
for
exclusive_cpu
in
exclusive_cpu_list
:
# gather tasks assigned to current exclusive CPU
task_path
=
os
.
path
.
join
(
self
.
cpuset_path
,
"cpu"
+
str
(
first_cpu
),
"tasks"
)
with
open
(
task_path
,
"rt"
)
as
fi
:
task_list
=
fi
.
read
().
split
()
if
len
(
task_list
)
>
0
:
continue
# skip occupied CPUs
with
open
(
task_path
,
"wt"
)
as
fo
:
fo
.
write
(
str
(
pid
))
return
exclusive_cpu
return
-
1
def
_prepare_folder
(
self
,
folder
):
"""If-Create folder and set group write permission."""
if
not
os
.
path
.
exists
(
folder
):
os
.
mkdir
(
folder
)
os
.
chown
(
folder
,
-
1
,
self
.
software_gid
)
# make your life and testing easier and create mandatory files if they don't exist
mandatory_file_list
=
(
"tasks"
,
"cpuset.cpus"
)
for
mandatory_file
in
mandatory_file_list
:
file_path
=
os
.
path
.
join
(
folder
,
mandatory_file
)
if
not
os
.
path
.
exists
(
file_path
):
with
open
(
file_path
,
"wb"
):
pass
# touche
return
folder
class
Computer
(
object
):
class
Computer
(
object
):
"Object representing the computer"
"""Object representing the computer"""
instance_root
=
None
software_root
=
None
instance_storage_home
=
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'
,
tap_gateway_interface
=
None
):
tap_gateway_interface
=
None
,
instance_root
=
None
,
software_root
=
None
,
instance_storage_home
=
None
,
partition_list
=
None
,
manager_list
=
None
):
"""
"""
Attributes:
Attributes:
reference:
String
, the reference of the computer.
reference:
str
, the reference of the computer.
interface:
String
, the name of the computer's used interface.
interface:
str
, the name of the computer's used interface.
"""
"""
self
.
reference
=
str
(
reference
)
self
.
reference
=
str
(
reference
)
self
.
interface
=
interface
self
.
interface
=
interface
self
.
partition_list
=
[]
self
.
partition_list
=
partition_list
or
[]
self
.
address
=
addr
self
.
address
=
addr
self
.
netmask
=
netmask
self
.
netmask
=
netmask
self
.
ipv6_interface
=
ipv6_interface
self
.
ipv6_interface
=
ipv6_interface
self
.
software_user
=
software_user
self
.
software_user
=
software_user
self
.
tap_gateway_interface
=
tap_gateway_interface
self
.
tap_gateway_interface
=
tap_gateway_interface
# The follow properties are updated on update() method
# Used to be static attributes of the class object - didn't make sense (Marco again)
assert
instance_root
is
not
None
and
software_root
is
not
None
,
"Computer's instance_root and software_root must not be empty!"
self
.
software_root
=
instance_root
self
.
instance_root
=
software_root
self
.
instance_storage_home
=
instance_storage_home
# The following properties are updated on update() method
self
.
public_ipv4_address
=
None
self
.
public_ipv4_address
=
None
self
.
os_type
=
None
self
.
os_type
=
None
self
.
python_version
=
None
self
.
python_version
=
None
self
.
slapos_version
=
None
self
.
slapos_version
=
None
# HASA relation to managers (could turn into plugins with `format` and `update` methods)
self
.
manager_list
=
(
manager
(
self
)
for
manager
in
manager_list
if
manager
(
self
).
allowed
())
\
if
manager_list
else
tuple
()
def
__getinitargs__
(
self
):
def
__getinitargs__
(
self
):
return
(
self
.
reference
,
self
.
interface
)
return
(
self
.
reference
,
self
.
interface
)
...
@@ -302,9 +460,11 @@ class Computer(object):
...
@@ -302,9 +460,11 @@ class Computer(object):
raise
NoAddressOnInterface
(
'No valid IPv6 found on %s.'
%
self
.
interface
.
name
)
raise
NoAddressOnInterface
(
'No valid IPv6 found on %s.'
%
self
.
interface
.
name
)
def
update
(
self
):
def
update
(
self
):
"""
"""Update computer runtime info and state."""
Collect environmental hardware/network information.
for
manager
in
self
.
manager_list
:
"""
manager
.
update
()
# Collect environmental hardware/network information.
self
.
public_ipv4_address
=
getPublicIPv4Address
()
self
.
public_ipv4_address
=
getPublicIPv4Address
()
self
.
slapos_version
=
version
.
version
self
.
slapos_version
=
version
.
version
self
.
python_version
=
platform
.
python_version
()
self
.
python_version
=
platform
.
python_version
()
...
@@ -390,7 +550,8 @@ class Computer(object):
...
@@ -390,7 +550,8 @@ class Computer(object):
archive
.
writestr
(
saved_filename
,
xml_content
,
zipfile
.
ZIP_DEFLATED
)
archive
.
writestr
(
saved_filename
,
xml_content
,
zipfile
.
ZIP_DEFLATED
)
@
classmethod
@
classmethod
def
load
(
cls
,
path_to_xml
,
reference
,
ipv6_interface
,
tap_gateway_interface
):
def
load
(
cls
,
path_to_xml
,
reference
,
ipv6_interface
,
tap_gateway_interface
instance_root
=
None
,
software_root
=
None
):
"""
"""
Create a computer object from a valid xml file.
Create a computer object from a valid xml file.
...
@@ -412,6 +573,8 @@ class Computer(object):
...
@@ -412,6 +573,8 @@ class Computer(object):
ipv6_interface
=
ipv6_interface
,
ipv6_interface
=
ipv6_interface
,
software_user
=
dumped_dict
.
get
(
'software_user'
,
'slapsoft'
),
software_user
=
dumped_dict
.
get
(
'software_user'
,
'slapsoft'
),
tap_gateway_interface
=
tap_gateway_interface
,
tap_gateway_interface
=
tap_gateway_interface
,
software_root
=
dumped_dict
.
get
(
'software_root'
,
software_root
),
instance_root
=
dumped_dict
.
get
(
'instance_root'
,
instance_root
),
)
)
for
i
,
partition_dict
in
enumerate
(
dumped_dict
[
'partition_list'
]):
for
i
,
partition_dict
in
enumerate
(
dumped_dict
[
'partition_list'
]):
...
@@ -494,61 +657,11 @@ class Computer(object):
...
@@ -494,61 +657,11 @@ class Computer(object):
def
software_gid
(
self
):
def
software_gid
(
self
):
"""Return GID for self.software_user.
"""Return GID for self.software_user.
Has to be dynamic because __init__ happens before ``
construc
t`` where we
Has to be dynamic because __init__ happens before ``
forma
t`` where we
effectively create the user and group."""
effectively create the user and group."""
return
pwd
.
getpwnam
(
self
.
software_user
)[
3
]
return
pwd
.
getpwnam
(
self
.
software_user
)[
3
]
def
format
(
self
,
alter_user
=
True
,
alter_network
=
True
,
create_tap
=
True
,
use_unique_local_address_block
=
False
):
def
_prepare_cgroup_folder
(
self
,
folder
):
"""If-Create folder and set group write permission."""
if
not
os
.
path
.
exists
(
folder
):
os
.
mkdir
(
folder
)
os
.
chown
(
folder
,
-
1
,
self
.
software_gid
)
return
folder
def
_prepare_cgroup_cpuset
(
self
):
"""Create cgroup folder per-CPU with exclusive access to the CPU.
Those folders are "/sys/fs/cgroup/cpuset/cpu<N>".
"""
if
not
os
.
path
.
exists
(
"/sys/fs/cgroup/cpuset/cpuset.cpus"
):
self
.
logger
.
warining
(
"Cannot prepare CGROUP CPUSET - not supported by current OS"
)
return
with
open
(
"/sys/fs/cgroup/cpuset/cpuset.cpus"
,
"rt"
)
as
cpu_def
:
# build up cpu_list of available CPU IDs
cpu_list
=
[]
# types: list[int]
for
cpu_def_split
in
cpu_def
.
read
().
strip
().
split
(
","
):
# IDs can be in form "0-4" or "0,1,2,3,4"
if
"-"
in
cpu_def_split
:
a
,
b
=
map
(
int
,
cpu_def_split
.
split
(
"-"
))
cpu_list
.
extend
(
range
(
a
,
b
+
1
))
# because cgroup's range is inclusive
continue
cpu_list
.
append
(
int
(
cpu_def_split
))
# For every CPU ID create an exclusive cgroup
for
cpu
in
cpu_list
:
cpu_path
=
self
.
_prepare_cgroup_folder
(
os
.
path
.
join
(
"/sys/fs/cgroup/cpuset/"
,
"cpu"
+
str
(
cpu
)))
with
open
(
cpu_path
+
"/cpuset.cpus"
,
"wt"
)
as
fx
:
fx
.
write
(
str
(
cpu
))
# this cgroup manages only this cpu
with
open
(
cpu_path
+
"/cpuset.cpu_exclusive"
,
"wt"
)
as
fx
:
fx
.
write
(
"1"
)
# manages it exclusively
os
.
chown
(
cpu_path
+
"/tasks"
,
-
1
,
self
.
software_gid
)
os
.
chmod
(
cpu_path
+
"/tasks"
,
0o664
)
def
prepare_cgroup
(
self
):
"""Build CGROUP tree exclusively for slapos.
- Create hierarchy of CPU sets so that every partition can have exclusive
hold of one of the CPUs.
"""
self
.
_prepare_cgroup_cpuset
()
def
construct
(
self
,
alter_user
=
True
,
alter_network
=
True
,
create_tap
=
True
,
use_unique_local_address_block
=
False
):
"""
"""
Setup underlaying OS so it reflects this instance (``self``).
Setup underlaying OS so it reflects this instance (``self``).
...
@@ -582,8 +695,9 @@ class Computer(object):
...
@@ -582,8 +695,9 @@ class Computer(object):
os
.
chown
(
slapsoft
.
path
,
slapsoft_pw
.
pw_uid
,
slapsoft_pw
.
pw_gid
)
os
.
chown
(
slapsoft
.
path
,
slapsoft_pw
.
pw_uid
,
slapsoft_pw
.
pw_gid
)
os
.
chmod
(
self
.
software_root
,
0o755
)
os
.
chmod
(
self
.
software_root
,
0o755
)
# Build own CGROUPS tree for resource control
# Iterate over all managers and let them `format` the computer too
self
.
prepare_cgroup
()
for
manager
in
self
.
manager_list
:
manager
.
format
()
# get list of instance external storage if exist
# get list of instance external storage if exist
instance_external_list
=
[]
instance_external_list
=
[]
...
@@ -1427,7 +1541,7 @@ def do_format(conf):
...
@@ -1427,7 +1541,7 @@ def do_format(conf):
if
conf
.
output_definition_file
:
if
conf
.
output_definition_file
:
write_computer_definition
(
conf
,
computer
)
write_computer_definition
(
conf
,
computer
)
computer
.
construc
t
(
alter_user
=
conf
.
alter_user
,
computer
.
forma
t
(
alter_user
=
conf
.
alter_user
,
alter_network
=
conf
.
alter_network
,
alter_network
=
conf
.
alter_network
,
create_tap
=
conf
.
create_tap
,
create_tap
=
conf
.
create_tap
,
use_unique_local_address_block
=
conf
.
use_unique_local_address_block
)
use_unique_local_address_block
=
conf
.
use_unique_local_address_block
)
...
...
slapos/tests/slapformat.py
View file @
d393206c
...
@@ -47,6 +47,20 @@ GROUP_LIST = []
...
@@ -47,6 +47,20 @@ GROUP_LIST = []
INTERFACE_DICT
=
{}
INTERFACE_DICT
=
{}
def
file_content
(
file_path
):
"""Read file(s) content."""
if
isinstance
(
file_path
,
(
list
,
tuple
)):
return
[
file_content
(
fx
)
for
fx
in
file_path
]
with
open
(
file_path
,
"rt"
)
as
fi
:
return
fi
.
read
().
strip
()
def
file_write
(
stuff
,
file_path
):
"""Write stuff into file_path."""
with
open
(
file_path
,
"wt"
)
as
fo
:
fo
.
write
(
stuff
)
class
FakeConfig
:
class
FakeConfig
:
pass
pass
...
@@ -158,6 +172,16 @@ class SlaposUtilMock:
...
@@ -158,6 +172,16 @@ class SlaposUtilMock:
def
chownDirectory
(
*
args
,
**
kw
):
def
chownDirectory
(
*
args
,
**
kw
):
pass
pass
class
CGroupManagerMock
(
slapos
.
format
.
CGroupManager
):
cpuset_path
=
"/tmp/cpuset/"
def
allowed
(
self
):
"""Always allowed."""
return
True
class
SlapformatMixin
(
unittest
.
TestCase
):
class
SlapformatMixin
(
unittest
.
TestCase
):
# keep big diffs
# keep big diffs
maxDiff
=
None
maxDiff
=
None
...
@@ -276,17 +300,17 @@ class TestComputer(SlapformatMixin):
...
@@ -276,17 +300,17 @@ class TestComputer(SlapformatMixin):
@
unittest
.
skip
(
"Not implemented"
)
@
unittest
.
skip
(
"Not implemented"
)
def
test_construct_empty
(
self
):
def
test_construct_empty
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
)
computer
=
slapos
.
format
.
Computer
(
'computer'
)
computer
.
construc
t
()
computer
.
forma
t
()
@
unittest
.
skip
(
"Not implemented"
)
@
unittest
.
skip
(
"Not implemented"
)
def
test_construct_empty_prepared
(
self
):
def
test_construct_empty_prepared
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
in
terface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
in
stance_root
=
'/instance_root'
,
name
=
'bridge
'
,
software_root
=
'/software_root
'
,
ipv4_local_network
=
'127.0.0.1/16'
))
interface
=
slapos
.
format
.
Interface
(
computer
.
instance_root
=
'/instance_root'
logger
=
self
.
logger
,
name
=
'bridge'
,
ipv4_local_network
=
'127.0.0.1/16'
),
computer
.
software_root
=
'/software_root'
partition_list
=
[])
computer
.
construc
t
()
computer
.
forma
t
()
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -302,12 +326,12 @@ class TestComputer(SlapformatMixin):
...
@@ -302,12 +326,12 @@ class TestComputer(SlapformatMixin):
def
test_construct_empty_prepared_no_alter_user
(
self
):
def
test_construct_empty_prepared_no_alter_user
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
in
terface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
in
stance_root
=
'/instance_root'
,
name
=
'bridge
'
,
software_root
=
'/software_root
'
,
ipv4_local_network
=
'127.0.0.1/16'
))
interface
=
slapos
.
format
.
Interface
(
computer
.
instance_root
=
'/instance_root'
logger
=
self
.
logger
,
name
=
'bridge'
,
ipv4_local_network
=
'127.0.0.1/16'
),
computer
.
software_root
=
'/software_root'
partition_list
=
[])
computer
.
construc
t
(
alter_user
=
False
)
computer
.
forma
t
(
alter_user
=
False
)
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -319,12 +343,12 @@ class TestComputer(SlapformatMixin):
...
@@ -319,12 +343,12 @@ class TestComputer(SlapformatMixin):
@
unittest
.
skip
(
"Not implemented"
)
@
unittest
.
skip
(
"Not implemented"
)
def
test_construct_empty_prepared_no_alter_network
(
self
):
def
test_construct_empty_prepared_no_alter_network
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
in
terface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
in
stance_root
=
'/instance_root'
,
name
=
'bridge
'
,
software_root
=
'/software_root
'
,
ipv4_local_network
=
'127.0.0.1/16'
))
interface
=
slapos
.
format
.
Interface
(
computer
.
instance_root
=
'/instance_root'
logger
=
self
.
logger
,
name
=
'bridge'
,
ipv4_local_network
=
'127.0.0.1/16'
),
computer
.
software_root
=
'/software_root'
partition_list
=
[])
computer
.
construc
t
(
alter_network
=
False
)
computer
.
forma
t
(
alter_network
=
False
)
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -340,12 +364,12 @@ class TestComputer(SlapformatMixin):
...
@@ -340,12 +364,12 @@ class TestComputer(SlapformatMixin):
def
test_construct_empty_prepared_no_alter_network_user
(
self
):
def
test_construct_empty_prepared_no_alter_network_user
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
in
terface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
in
stance_root
=
'/instance_root'
,
name
=
'bridge
'
,
software_root
=
'/software_root
'
,
ipv4_local_network
=
'127.0.0.1/16'
))
interface
=
slapos
.
format
.
Interface
(
computer
.
instance_root
=
'/instance_root'
logger
=
self
.
logger
,
name
=
'bridge'
,
ipv4_local_network
=
'127.0.0.1/16'
),
computer
.
software_root
=
'/software_root'
partition_list
=
[])
computer
.
construc
t
(
alter_network
=
False
,
alter_user
=
False
)
computer
.
forma
t
(
alter_network
=
False
,
alter_user
=
False
)
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -359,15 +383,15 @@ class TestComputer(SlapformatMixin):
...
@@ -359,15 +383,15 @@ class TestComputer(SlapformatMixin):
@
unittest
.
skip
(
"Not implemented"
)
@
unittest
.
skip
(
"Not implemented"
)
def
test_construct_prepared
(
self
):
def
test_construct_prepared
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
in
terface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
in
stance_root
=
'/instance_root'
,
name
=
'bridge
'
,
software_root
=
'/software_root
'
,
ipv4_local_network
=
'127.0.0.1/16'
))
interface
=
slapos
.
format
.
Interface
(
computer
.
instance_root
=
'/instance_root'
logger
=
self
.
logger
,
name
=
'bridge'
,
ipv4_local_network
=
'127.0.0.1/16'
),
computer
.
software_root
=
'/software_root'
partition_list
=
[
partition
=
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
Partition
(
slapos
.
format
.
User
(
'testuser'
),
[],
None
)
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
partition
.
tap
=
slapos
.
format
.
Tap
(
'tap'
)
]
)
computer
.
partition_list
=
[
partition
]
global
INTERFACE_DICT
global
INTERFACE_DICT
INTERFACE_DICT
[
'bridge'
]
=
{
INTERFACE_DICT
[
'bridge'
]
=
{
socket
.
AF_INET
:
[{
'addr'
:
'192.168.242.77'
,
'broadcast'
:
'127.0.0.1'
,
socket
.
AF_INET
:
[{
'addr'
:
'192.168.242.77'
,
'broadcast'
:
'127.0.0.1'
,
...
@@ -375,7 +399,7 @@ class TestComputer(SlapformatMixin):
...
@@ -375,7 +399,7 @@ class TestComputer(SlapformatMixin):
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
}
}
computer
.
construc
t
()
computer
.
forma
t
()
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -405,13 +429,15 @@ class TestComputer(SlapformatMixin):
...
@@ -405,13 +429,15 @@ class TestComputer(SlapformatMixin):
def
test_construct_prepared_no_alter_user
(
self
):
def
test_construct_prepared_no_alter_user
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
interface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
instance_root
=
'/instance_root'
,
name
=
'bridge'
,
software_root
=
'/software_root'
,
ipv4_local_network
=
'127.0.0.1/16'
))
interface
=
slapos
.
format
.
Interface
(
computer
.
instance_root
=
'/instance_root'
logger
=
self
.
logger
,
name
=
'bridge'
,
ipv4_local_network
=
'127.0.0.1/16'
),
computer
.
software_root
=
'/software_root'
partition_list
=
[
partition
=
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
Partition
(
slapos
.
format
.
User
(
'testuser'
),
[],
None
)
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
None
),
])
global
USER_LIST
global
USER_LIST
USER_LIST
=
[
'testuser'
]
USER_LIST
=
[
'testuser'
]
partition
.
tap
=
slapos
.
format
.
Tap
(
'tap'
)
partition
.
tap
=
slapos
.
format
.
Tap
(
'tap'
)
...
@@ -423,7 +449,7 @@ class TestComputer(SlapformatMixin):
...
@@ -423,7 +449,7 @@ class TestComputer(SlapformatMixin):
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
}
}
computer
.
construc
t
(
alter_user
=
False
)
computer
.
forma
t
(
alter_user
=
False
)
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -447,14 +473,14 @@ class TestComputer(SlapformatMixin):
...
@@ -447,14 +473,14 @@ class TestComputer(SlapformatMixin):
def
test_construct_prepared_tap_no_alter_user
(
self
):
def
test_construct_prepared_tap_no_alter_user
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
in
terface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
in
stance_root
=
'/instance_root'
,
name
=
'iface
'
,
software_root
=
'/software_root
'
,
ipv4_local_network
=
'127.0.0.1/16'
),
interface
=
slapos
.
format
.
Interface
(
tap_gateway_interface
=
'eth1'
)
logger
=
self
.
logger
,
name
=
'iface'
,
ipv4_local_network
=
'127.0.0.1/16'
,
tap_gateway_interface
=
'eth1'
),
computer
.
instance_root
=
'/instance_root'
partition_list
=
[
computer
.
software_root
=
'/software_root'
slapos
.
format
.
Partition
(
partition
=
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
None
)
,
slapos
.
format
.
User
(
'testuser'
),
[],
None
)
]
)
global
USER_LIST
global
USER_LIST
USER_LIST
=
[
'testuser'
]
USER_LIST
=
[
'testuser'
]
partition
.
tap
=
slapos
.
format
.
Tap
(
'tap'
)
partition
.
tap
=
slapos
.
format
.
Tap
(
'tap'
)
...
@@ -470,7 +496,7 @@ class TestComputer(SlapformatMixin):
...
@@ -470,7 +496,7 @@ class TestComputer(SlapformatMixin):
'netmask'
:
'255.255.255.0'
}]
'netmask'
:
'255.255.255.0'
}]
}
}
computer
.
construc
t
(
alter_user
=
False
)
computer
.
forma
t
(
alter_user
=
False
)
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -498,15 +524,15 @@ class TestComputer(SlapformatMixin):
...
@@ -498,15 +524,15 @@ class TestComputer(SlapformatMixin):
@
unittest
.
skip
(
"Not implemented"
)
@
unittest
.
skip
(
"Not implemented"
)
def
test_construct_prepared_no_alter_network
(
self
):
def
test_construct_prepared_no_alter_network
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
in
terface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
in
stance_root
=
'/instance_root'
,
name
=
'bridge
'
,
software_root
=
'/software_root
'
,
ipv4_local_network
=
'127.0.0.1/16'
))
interface
=
slapos
.
format
.
Interface
(
computer
.
instance_root
=
'/instance_root'
logger
=
self
.
logger
,
name
=
'bridge'
,
ipv4_local_network
=
'127.0.0.1/16'
),
computer
.
software_root
=
'/software_root'
partition_list
=
[
partition
=
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
Partition
(
slapos
.
format
.
User
(
'testuser'
),
[],
None
)
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
partition
.
tap
=
slapos
.
format
.
Tap
(
'tap'
)
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
computer
.
partition_list
=
[
partition
]
])
global
INTERFACE_DICT
global
INTERFACE_DICT
INTERFACE_DICT
[
'bridge'
]
=
{
INTERFACE_DICT
[
'bridge'
]
=
{
socket
.
AF_INET
:
[{
'addr'
:
'192.168.242.77'
,
'broadcast'
:
'127.0.0.1'
,
socket
.
AF_INET
:
[{
'addr'
:
'192.168.242.77'
,
'broadcast'
:
'127.0.0.1'
,
...
@@ -514,7 +540,7 @@ class TestComputer(SlapformatMixin):
...
@@ -514,7 +540,7 @@ class TestComputer(SlapformatMixin):
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
}
}
computer
.
construc
t
(
alter_network
=
False
)
computer
.
forma
t
(
alter_network
=
False
)
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -540,15 +566,15 @@ class TestComputer(SlapformatMixin):
...
@@ -540,15 +566,15 @@ class TestComputer(SlapformatMixin):
def
test_construct_prepared_no_alter_network_user
(
self
):
def
test_construct_prepared_no_alter_network_user
(
self
):
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
in
terface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
in
stance_root
=
'/instance_root'
,
name
=
'bridge
'
,
software_root
=
'/software_root
'
,
ipv4_local_network
=
'127.0.0.1/16'
))
interface
=
slapos
.
format
.
Interface
(
computer
.
instance_root
=
'/instance_root'
logger
=
self
.
logger
,
name
=
'bridge'
,
ipv4_local_network
=
'127.0.0.1/16'
),
computer
.
software_root
=
'/software_root'
partition_list
=
[
partition
=
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
Partition
(
slapos
.
format
.
User
(
'testuser'
),
[],
None
)
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
partition
.
tap
=
slapos
.
format
.
Tap
(
'tap'
)
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
computer
.
partition_list
=
[
partition
]
])
global
INTERFACE_DICT
global
INTERFACE_DICT
INTERFACE_DICT
[
'bridge'
]
=
{
INTERFACE_DICT
[
'bridge'
]
=
{
socket
.
AF_INET
:
[{
'addr'
:
'192.168.242.77'
,
'broadcast'
:
'127.0.0.1'
,
socket
.
AF_INET
:
[{
'addr'
:
'192.168.242.77'
,
'broadcast'
:
'127.0.0.1'
,
...
@@ -556,7 +582,7 @@ class TestComputer(SlapformatMixin):
...
@@ -556,7 +582,7 @@ class TestComputer(SlapformatMixin):
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
}
}
computer
.
construc
t
(
alter_network
=
False
,
alter_user
=
False
)
computer
.
forma
t
(
alter_network
=
False
,
alter_user
=
False
)
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -581,15 +607,15 @@ class TestComputer(SlapformatMixin):
...
@@ -581,15 +607,15 @@ class TestComputer(SlapformatMixin):
global
USER_LIST
global
USER_LIST
USER_LIST
=
[
'root'
]
USER_LIST
=
[
'root'
]
computer
=
slapos
.
format
.
Computer
(
'computer'
,
computer
=
slapos
.
format
.
Computer
(
'computer'
,
in
terface
=
slapos
.
format
.
Interface
(
logger
=
self
.
test_result
,
in
stance_root
=
'/instance_root'
,
name
=
'myinterface
'
,
software_root
=
'/software_root
'
,
ipv4_local_network
=
'127.0.0.1/16'
))
interface
=
slapos
.
format
.
Interface
(
computer
.
instance_root
=
'/instance_root'
logger
=
self
.
logger
,
name
=
'myinterface'
,
ipv4_local_network
=
'127.0.0.1/16'
),
computer
.
software_root
=
'/software_root'
partition_list
=
[
partition
=
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
Partition
(
slapos
.
format
.
User
(
'testuser'
),
[],
None
)
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
partition
.
tap
=
slapos
.
format
.
Tap
(
'tap'
)
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
computer
.
partition_list
=
[
partition
]
])
global
INTERFACE_DICT
global
INTERFACE_DICT
INTERFACE_DICT
[
'myinterface'
]
=
{
INTERFACE_DICT
[
'myinterface'
]
=
{
socket
.
AF_INET
:
[{
'addr'
:
'192.168.242.77'
,
'broadcast'
:
'127.0.0.1'
,
socket
.
AF_INET
:
[{
'addr'
:
'192.168.242.77'
,
'broadcast'
:
'127.0.0.1'
,
...
@@ -597,7 +623,7 @@ class TestComputer(SlapformatMixin):
...
@@ -597,7 +623,7 @@ class TestComputer(SlapformatMixin):
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
socket
.
AF_INET6
:
[{
'addr'
:
'2a01:e35:2e27::e59c'
,
'netmask'
:
'ffff:ffff:ffff:ffff::'
}]
}
}
computer
.
construc
t
(
use_unique_local_address_block
=
True
,
alter_user
=
False
,
create_tap
=
False
)
computer
.
forma
t
(
use_unique_local_address_block
=
True
,
alter_user
=
False
,
create_tap
=
False
)
self
.
assertEqual
([
self
.
assertEqual
([
"makedirs('/instance_root', 493)"
,
"makedirs('/instance_root', 493)"
,
"makedirs('/software_root', 493)"
,
"makedirs('/software_root', 493)"
,
...
@@ -615,6 +641,68 @@ class TestComputer(SlapformatMixin):
...
@@ -615,6 +641,68 @@ class TestComputer(SlapformatMixin):
],
],
self
.
fakeCallAndRead
.
external_command_list
)
self
.
fakeCallAndRead
.
external_command_list
)
class
TestComputerWithCGroup
(
SlapformatMixin
):
def
setUp
(
self
):
super
(
TestComputerWithCGroup
,
self
).
setUp
()
self
.
restoreOs
()
os
.
mkdir
(
"/tmp/slapgrid/"
)
os
.
mkdir
(
CGroupManagerMock
.
cpuset_path
)
with
open
(
os
.
path
.
join
(
CGroupManagerMock
.
cpuset_path
,
"cpuset.cpus"
),
"wt"
)
as
fo
:
fo
.
write
(
"0,1-3"
)
self
.
cpu_list
=
[
0
,
1
,
2
,
3
]
with
open
(
os
.
path
.
join
(
CGroupManagerMock
.
cpuset_path
,
"tasks"
),
"wt"
)
as
fo
:
fo
.
writelines
((
"1000
\
n
"
,
"1001
\
n
"
,
"1002
\
n
"
))
self
.
computer
=
slapos
.
format
.
Computer
(
'computer'
,
instance_root
=
'/tmp/slapgrid/instance_root'
,
software_root
=
'/tmp/slapgrid/software_root'
,
interface
=
slapos
.
format
.
Interface
(
logger
=
self
.
logger
,
name
=
'bridge'
,
ipv4_local_network
=
'127.0.0.1/16'
),
partition_list
=
[
slapos
.
format
.
Partition
(
'partition'
,
'/tmp/slapgrid/instance_root/part1'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
None
),
],
manager_list
=
(
CGroupManagerMock
,
)
)
def
tearDown
(
self
):
shutil
.
rmtree
(
CGroupManagerMock
.
cpuset_path
)
super
(
TestComputerWithCGroup
,
self
).
tearDown
()
def
test_positive_cgroups
(
self
):
"""Positive test of cgroups."""
self
.
computer
.
format
(
alter_network
=
False
,
alter_user
=
False
)
# Test parsing "cpuset.cpus" file
self
.
assertEqual
(
self
.
computer
.
manager_list
[
0
].
_cpu_list
(),
self
.
cpu_list
)
# Test files creation for exclusive CPUs
for
cpu_id
in
self
.
cpu_list
:
cpu_n_path
=
os
.
path
.
join
(
CGroupManagerMock
.
cpuset_path
,
"cpu"
+
str
(
cpu_id
))
self
.
assertEqual
(
str
(
cpu_id
),
file_content
(
os
.
path
.
join
(
cpu_n_path
,
"cpuset.cpus"
)))
self
.
assertEqual
(
"1"
,
file_content
(
os
.
path
.
join
(
cpu_n_path
,
"cpuset.cpu_exclusive"
)))
if
cpu_id
>
0
:
self
.
assertEqual
(
""
,
file_content
(
os
.
path
.
join
(
cpu_n_path
,
"tasks"
)))
# Test that format moved all PIDs from CPU pool into CPU0
tasks_at_cpu0
=
file_content
(
os
.
path
.
join
(
CGroupManagerMock
.
cpuset_path
,
"cpu0"
,
"tasks"
)).
split
()
self
.
assertIn
(
"1000"
,
tasks_at_cpu0
)
self
.
assertIn
(
"1001"
,
tasks_at_cpu0
)
self
.
assertIn
(
"1002"
,
tasks_at_cpu0
)
# Simulate cgroup behaviour - empty tasks in the pool
file_write
(
""
,
os
.
path
.
join
(
CGroupManagerMock
.
cpuset_path
,
"tasks"
))
# test moving tasks from generic core to private core
# request PID 1001 to be moved to its private CPU
file_write
(
"1001
\
n
"
,
os
.
path
.
join
(
self
.
computer
.
partition_list
.
path
,
CGroupManagerMock
.
cpu_exclusive_file
))
# let format do the moving
self
.
computer
.
update
()
# test if the moving suceeded into any provate CPUS (id>0)
self
.
assertTrue
(
any
(
"1001"
in
file_content
(
exclusive_task
)
for
exclusive_task
in
glob
.
glob
(
os
.
path
.
join
(
CGroupManagerMock
.
cpuset_path
,
"cpu[1-9]"
,
"tasks"
))))
class
TestPartition
(
SlapformatMixin
):
class
TestPartition
(
SlapformatMixin
):
def
test_createPath_no_alter_user
(
self
):
def
test_createPath_no_alter_user
(
self
):
...
...
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