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
Jérome Perrin
slapos.core
Commits
656a5721
Commit
656a5721
authored
May 11, 2020
by
Jérome Perrin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP type defintions
parent
34d7fb60
Changes
13
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
165 additions
and
39 deletions
+165
-39
mypy.ini
mypy.ini
+17
-0
setup.py
setup.py
+2
-1
slapos/__init__.py
slapos/__init__.py
+1
-1
slapos/cli/proxy_show.py
slapos/cli/proxy_show.py
+1
-1
slapos/collect/temperature/__init__.py
slapos/collect/temperature/__init__.py
+7
-3
slapos/grid/SlapObject.py
slapos/grid/SlapObject.py
+2
-1
slapos/grid/slapgrid.py
slapos/grid/slapgrid.py
+14
-8
slapos/grid/svcbackend.py
slapos/grid/svcbackend.py
+1
-1
slapos/proxy/views.py
slapos/proxy/views.py
+10
-4
slapos/slap/slap.py
slapos/slap/slap.py
+57
-6
slapos/slap/standalone.py
slapos/slap/standalone.py
+41
-7
slapos/tests/test_prune.py
slapos/tests/test_prune.py
+4
-3
slapos/tests/test_slapproxy.py
slapos/tests/test_slapproxy.py
+8
-3
No files found.
mypy.ini
0 → 100644
View file @
656a5721
[mypy]
ignore_missing_imports
=
True
[mypy-slapos]
ignore_missing_imports
=
True
[mypy-slapos.slap]
ignore_missing_imports
=
True
[mypy-slapos.slap.grid]
ignore_missing_imports
=
True
# interfaces cause error: Method must have at least one argument
[mypy-slapos.slap.interface]
ignore_errors
=
True
[mypy-slapos.slap.interface.slap]
ignore_errors
=
True
setup.py
View file @
656a5721
...
...
@@ -75,7 +75,8 @@ setup(name=name,
'cachecontrol'
,
'lockfile'
,
'uritemplate'
,
# used by hateoas navigator
'subprocess32; python_version<"3"'
'subprocess32; python_version<"3"'
,
'typing; python_version<"3"'
,
]
+
additional_install_requires
,
extras_require
=
extras_require
,
tests_require
=
extras_require
[
'test'
],
...
...
slapos/__init__.py
View file @
656a5721
...
...
@@ -3,4 +3,4 @@ try:
__import__
(
'pkg_resources'
).
declare_namespace
(
__name__
)
except
ImportError
:
from
pkgutil
import
extend_path
__path__
=
extend_path
(
__path__
,
__name__
)
__path__
=
extend_path
(
__path__
,
__name__
)
# type: ignore
slapos/cli/proxy_show.py
View file @
656a5721
...
...
@@ -44,7 +44,7 @@ from slapos.proxy import ProxyConfig
from
slapos.proxy.db_version
import
DB_VERSION
from
slapos.util
import
sqlite_connect
,
str2bytes
if
bytes
is
str
:
if
sys
.
version_info
[
0
]
==
3
:
from
io
import
BytesIO
class
StringIO
(
BytesIO
):
# Something between strict io.BytesIO and laxist/slow StringIO.StringIO
...
...
slapos/collect/temperature/__init__.py
View file @
656a5721
from
__future__
import
print_function
from
multiprocessing
import
Process
,
active_children
,
cpu_count
,
Pipe
try
:
import
subprocess32
as
subprocess
except
ImportError
:
from
typing
import
TYPE_CHECKING
if
TYPE_CHECKING
:
import
subprocess
else
:
try
:
import
subprocess32
as
subprocess
except
ImportError
:
import
subprocess
import
os
import
signal
import
sys
...
...
slapos/grid/SlapObject.py
View file @
656a5721
...
...
@@ -38,7 +38,8 @@ import subprocess
import
tarfile
import
tempfile
import
time
from
six.moves
import
xmlrpc_client
as
xmlrpclib
,
range
from
six.moves
import
xmlrpc_client
as
xmlrpclib
# type: ignore
from
six.moves
import
range
from
six.moves.configparser
import
ConfigParser
from
supervisor
import
xmlrpc
...
...
slapos/grid/slapgrid.py
View file @
656a5721
...
...
@@ -49,6 +49,10 @@ if sys.version_info < (2, 6):
warnings
.
warn
(
'Used python version (%s) is old and has problems with'
' IPv6 connections'
%
sys
.
version
.
split
(
'
\
n
'
)[
0
])
from
typing
import
List
,
Tuple
,
Sequence
,
TYPE_CHECKING
if
TYPE_CHECKING
:
from
..slap.slap
import
ComputerPartition
from
lxml
import
etree
from
slapos
import
manager
as
slapmanager
...
...
@@ -537,6 +541,7 @@ stderr_logfile_backups=1
launchSupervisord
(
instance_root
=
self
.
instance_root
,
logger
=
self
.
logger
)
def
getComputerPartitionList
(
self
):
# type: () -> Sequence[ComputerPartition]
try
:
return
self
.
computer
.
getComputerPartitionList
()
except
socket
.
error
as
exc
:
...
...
@@ -789,7 +794,7 @@ stderr_logfile_backups=1
reload_process
=
FPopen
(
reload_cmd
,
universal_newlines
=
True
)
stdout
,
stderr
=
reload_process
.
communicate
()
if
reload_process
.
returncode
!=
0
:
raise
Exception
(
"Failed to load firewalld rules with command %s.
\
n
%"
%
(
raise
Exception
(
"Failed to load firewalld rules with command %s.
\
n
%
s
"
%
(
stderr
,
reload_cmd
))
with
open
(
firewall_rules_path
,
'w'
)
as
frules
:
...
...
@@ -1254,6 +1259,7 @@ stderr_logfile_backups=1
f
.
write
(
str
(
timestamp
))
def
FilterComputerPartitionList
(
self
,
computer_partition_list
):
# type: (Sequence[ComputerPartition]) -> List[ComputerPartition]
"""
Try to filter valid partitions to be processed from free partitions.
"""
...
...
@@ -1392,12 +1398,12 @@ stderr_logfile_backups=1
self
.
logger
.
info
(
'='
*
80
)
if
process_error_partition_list
:
self
.
logger
.
info
(
'Error while processing the following partitions:'
)
for
partition
,
e
xc
in
process_error_partition_list
:
self
.
logger
.
info
(
' %s[%s]: %s'
,
partition
.
getId
(),
getPartitionType
(
partition
),
e
xc
)
for
partition
,
e
rror
in
process_error_partition_list
:
self
.
logger
.
info
(
' %s[%s]: %s'
,
partition
.
getId
(),
getPartitionType
(
partition
),
e
rror
)
if
promise_error_partition_list
:
self
.
logger
.
info
(
'Error with promises for the following partitions:'
)
for
partition
,
e
xc
in
promise_error_partition_list
:
self
.
logger
.
info
(
' %s[%s]: %s'
,
partition
.
getId
(),
getPartitionType
(
partition
),
e
xc
)
for
partition
,
e
rror
in
promise_error_partition_list
:
self
.
logger
.
info
(
' %s[%s]: %s'
,
partition
.
getId
(),
getPartitionType
(
partition
),
e
rror
)
# Return success value
if
not
clean_run
:
...
...
@@ -1420,7 +1426,7 @@ stderr_logfile_backups=1
computer_partition_list
=
self
.
FilterComputerPartitionList
(
self
.
getComputerPartitionList
())
promise_error_partition_list
=
[]
promise_error_partition_list
=
[]
# type: List[Tuple[ComputerPartition, Union[PromiseError, Exception]]]
for
computer_partition
in
computer_partition_list
:
try
:
# Process the partition itself
...
...
@@ -1444,8 +1450,8 @@ stderr_logfile_backups=1
if
promise_error_partition_list
:
self
.
logger
.
info
(
'Finished computer partitions.'
)
for
partition
,
e
xc
in
promise_error_partition_list
:
self
.
logger
.
info
(
' %s[%s]: %s'
,
partition
.
getId
(),
getPartitionType
(
partition
),
e
xc
)
for
partition
,
e
rror
in
promise_error_partition_list
:
self
.
logger
.
info
(
' %s[%s]: %s'
,
partition
.
getId
(),
getPartitionType
(
partition
),
e
rror
)
# Return success value
if
not
clean_run_promise
:
...
...
slapos/grid/svcbackend.py
View file @
656a5721
...
...
@@ -35,7 +35,7 @@ import subprocess
import
stat
import
sys
import
time
from
six.moves
import
xmlrpc_client
as
xmlrpclib
from
six.moves
import
xmlrpc_client
as
xmlrpclib
# type: ignore
import
contextlib
from
slapos.grid.utils
import
(
createPrivateDirectory
,
SlapPopen
,
updateFile
)
...
...
slapos/proxy/views.py
View file @
656a5721
...
...
@@ -53,8 +53,11 @@ EMPTY_DICT_XML = dumps({})
class
UnauthorizedError
(
Exception
):
pass
from
typing
import
Dict
,
Union
,
no_type_check
@
no_type_check
def
partitiondict2partition
(
partition
):
# type: (Dict[str, str]) -> ComputerPartition
slap_partition
=
ComputerPartition
(
partition
[
'computer_reference'
],
partition
[
'reference'
])
slap_partition
.
_software_release_document
=
None
...
...
@@ -365,6 +368,7 @@ def supplySupply():
@
app
.
route
(
'/requestComputerPartition'
,
methods
=
[
'POST'
])
def
requestComputerPartition
():
# type: () -> str
parsed_request_dict
=
parseRequestComputerPartitionForm
(
request
.
form
)
# Is it a slave instance?
slave
=
loads
(
request
.
form
.
get
(
'shared_xml'
,
EMPTY_DICT_XML
).
encode
(
'utf-8'
))
...
...
@@ -457,6 +461,7 @@ def requestComputerPartition():
return
dumps
(
software_instance
)
def
parseRequestComputerPartitionForm
(
form
):
# type: (Dict) -> Dict
"""
Parse without intelligence a form from a request(), return it.
"""
...
...
@@ -469,7 +474,7 @@ def parseRequestComputerPartitionForm(form):
'filter_kw'
:
loads
(
form
.
get
(
'filter_xml'
,
EMPTY_DICT_XML
).
encode
(
'utf-8'
)),
# Note: currently ignored for slave instance (slave instances
# are always started).
'requested_state'
:
loads
(
form
.
get
(
'state'
)
.
encode
(
'utf-8'
)),
'requested_state'
:
loads
(
form
[
'state'
]
.
encode
(
'utf-8'
)),
}
return
parsed_dict
...
...
@@ -543,10 +548,11 @@ def isRequestToBeForwardedToExternalMaster(parsed_request_dict):
return
None
def
forwardRequestToExternalMaster
(
master_url
,
request_form
):
# type: (str, Dict) -> str
"""
Forward instance request to external SlapOS Master.
"""
master_entry
=
app
.
config
.
get
(
'multimaster'
)
.
get
(
master_url
,
{})
master_entry
=
app
.
config
[
'multimaster'
]
.
get
(
master_url
,
{})
key_file
=
master_entry
.
get
(
'key'
)
cert_file
=
master_entry
.
get
(
'cert'
)
if
master_url
.
startswith
(
'https'
)
and
(
not
key_file
or
not
cert_file
):
...
...
@@ -568,7 +574,7 @@ def forwardRequestToExternalMaster(master_url, request_form):
{
'partition_reference'
:
partition_reference
,
'master_url'
:
master_url
})
new_request_form
=
request_form
.
copy
()
filter_kw
=
loads
(
new_
request_form
[
'filter_xml'
].
encode
(
'utf-8'
))
filter_kw
=
loads
(
request_form
[
'filter_xml'
].
encode
(
'utf-8'
))
filter_kw
[
'source_instance_id'
]
=
partition_reference
new_request_form
[
'filter_xml'
]
=
dumps
(
filter_kw
)
...
...
@@ -576,7 +582,7 @@ def forwardRequestToExternalMaster(master_url, request_form):
partition
=
loads
(
xml
)
# XXX move to other end
partition
.
_master_url
=
master_url
partition
.
_master_url
=
master_url
# type: ignore
return
dumps
(
partition
)
...
...
slapos/slap/slap.py
View file @
656a5721
This diff is collapsed.
Click to expand it.
slapos/slap/standalone.py
View file @
656a5721
...
...
@@ -38,10 +38,16 @@ import shutil
from
six.moves
import
urllib
from
six.moves
import
http_client
try
:
import
subprocess32
as
subprocess
except
ImportError
:
from
typing
import
TYPE_CHECKING
,
Optional
,
Iterable
,
Dict
if
TYPE_CHECKING
:
import
subprocess
from
..slap.slap
import
Computer
,
ComputerPartition
,
SoftwareState
,
InstanceState
,
PartitionParameters
,
FilterParameters
else
:
try
:
import
subprocess32
as
subprocess
except
ImportError
:
import
subprocess
import
xml_marshaller
import
zope.interface
...
...
@@ -80,9 +86,11 @@ class ConfigWriter(object):
"""Base class for an object writing a config file or wrapper script.
"""
def
__init__
(
self
,
standalone_slapos
):
# type: (StandaloneSlapOS) -> None
self
.
_standalone_slapos
=
standalone_slapos
def
writeConfig
(
self
,
path
):
# type: (str) -> None
NotImplemented
...
...
@@ -90,6 +98,7 @@ class SupervisorConfigWriter(ConfigWriter):
"""Write supervisor configuration at etc/supervisor.conf
"""
def
_getProgramConfig
(
self
,
program_name
,
command
,
stdout_logfile
):
# type: (str, str, str) -> str
"""Format a supervisor program block.
"""
return
textwrap
.
dedent
(
...
...
@@ -108,6 +117,7 @@ class SupervisorConfigWriter(ConfigWriter):
"""
).
format
(
**
locals
())
def
_getSupervisorConfigParts
(
self
):
# type: () -> Iterable[str]
"""Iterator on parts of formatted config.
"""
standalone_slapos
=
self
.
_standalone_slapos
...
...
@@ -143,6 +153,7 @@ class SupervisorConfigWriter(ConfigWriter):
'stdout_logfile'
,
'AUTO'
).
format
(
self
=
standalone_slapos
))
def
writeConfig
(
self
,
path
):
# type: (str) -> None
with
open
(
path
,
'w'
)
as
f
:
for
part
in
self
.
_getSupervisorConfigParts
():
f
.
write
(
part
)
...
...
@@ -151,8 +162,10 @@ class SupervisorConfigWriter(ConfigWriter):
class
SlapOSConfigWriter
(
ConfigWriter
):
"""Write slapos configuration at etc/slapos.cfg
"""
def
writeConfig
(
self
,
path
):
standalone_slapos
=
self
.
_standalone_slapos
# type: StandaloneSlapOS
# type: (str) -> None
standalone_slapos
=
self
.
_standalone_slapos
read_only_shared_part_list
=
'
\
n
'
.
join
(
# pylint: disable=unused-variable; used in format()
standalone_slapos
.
_shared_part_list
)
with
open
(
path
,
'w'
)
as
f
:
...
...
@@ -183,6 +196,7 @@ class SlapOSCommandWriter(ConfigWriter):
"""Write a bin/slapos wrapper.
"""
def
writeConfig
(
self
,
path
):
# type: (str) -> None
with
open
(
path
,
'w'
)
as
f
:
f
.
write
(
textwrap
.
dedent
(
...
...
@@ -215,7 +229,9 @@ class StandaloneSlapOS(object):
shared_part_list
=
(),
software_root
=
None
,
instance_root
=
None
,
shared_part_root
=
None
):
shared_part_root
=
None
,
):
# type: (str, str, int, str, Iterable[str], Optional[str], Optional[str], Optional[str]) -> None
"""Constructor, creates a standalone slapos in `base_directory`.
Arguments:
...
...
@@ -273,6 +289,7 @@ class StandaloneSlapOS(object):
self
.
_initBaseDirectory
(
software_root
,
instance_root
,
shared_part_root
)
def
_initBaseDirectory
(
self
,
software_root
,
instance_root
,
shared_part_root
):
# type: (Optional[str], Optional[str], Optional[str]) -> None
"""Create the directory after checking it's not too deep.
"""
base_directory
=
self
.
_base_directory
...
...
@@ -337,6 +354,7 @@ class StandaloneSlapOS(object):
@
property
def
computer
(
self
):
# type: () -> Computer
"""Access the computer.
"""
return
self
.
_slap
.
registerComputer
(
self
.
_computer_id
)
...
...
@@ -391,6 +409,7 @@ class StandaloneSlapOS(object):
ipv4_address
,
ipv6_address
,
partition_base_name
=
"slappart"
):
# type: (int, str, str, str) -> None
"""Creates `partition_count` partitions.
All partitions have the same `ipv4_address` and `ipv6_address` and
...
...
@@ -489,6 +508,7 @@ class StandaloneSlapOS(object):
os
.
unlink
(
supervisor_conf
)
def
supply
(
self
,
software_url
,
computer_guid
=
None
,
state
=
"available"
):
# type: (str, Optional[str], SoftwareState) -> None
"""Supply a software, see ISupply.supply
Software can only be supplied on this embedded computer.
...
...
@@ -510,6 +530,7 @@ class StandaloneSlapOS(object):
partition_parameter_kw
=
None
,
filter_kw
=
None
,
state
=
None
):
# type: (str, str, Optional[str], bool, Optional[PartitionParameters], Optional[FilterParameters], Optional[InstanceState]) -> ComputerPartition
"""Request an instance, see IRequester.request
Instance can only be requested on this embedded computer.
...
...
@@ -526,6 +547,7 @@ class StandaloneSlapOS(object):
state
=
state
)
def
start
(
self
):
# type: () -> None
"""Start the system.
If system was stopped, it will start partitions.
...
...
@@ -536,6 +558,7 @@ class StandaloneSlapOS(object):
self
.
_ensureSlapOSAvailable
()
def
stop
(
self
):
# type: () -> None
"""Stops all services.
This methods blocks until services are stopped or a timeout is reached.
...
...
@@ -573,6 +596,7 @@ class StandaloneSlapOS(object):
alive
+
instance_process_alive
))
def
waitForSoftware
(
self
,
max_retry
=
0
,
debug
=
False
,
error_lines
=
30
):
# type: (int, bool, int) -> None
"""Synchronously install or uninstall all softwares previously supplied/removed.
This method retries on errors. If after `max_retry` times there's
...
...
@@ -594,6 +618,7 @@ class StandaloneSlapOS(object):
)
def
waitForInstance
(
self
,
max_retry
=
0
,
debug
=
False
,
error_lines
=
30
):
# type: (int, bool, int) -> None
"""Instantiate all partitions previously requested for start.
This method retries on errors. If after `max_retry` times there's
...
...
@@ -615,6 +640,7 @@ class StandaloneSlapOS(object):
)
def
waitForReport
(
self
,
max_retry
=
0
,
debug
=
False
,
error_lines
=
30
):
# type: (int, bool, int) -> None
"""Destroy all partitions previously requested for destruction.
This method retries on errors. If after `max_retry` times there's
...
...
@@ -637,17 +663,19 @@ class StandaloneSlapOS(object):
def
_runSlapOSCommand
(
self
,
command
,
max_retry
=
0
,
debug
=
False
,
error_lines
=
30
):
# type: (str, int, bool, int) -> None
if
debug
:
prog
=
self
.
_slapos_commands
[
command
]
# used in format(**locals()) below
debug_args
=
prog
.
get
(
'debug_args'
,
''
)
# pylint: disable=unused-variable
command
=
prog
[
'command'
].
format
(
**
locals
())
try
:
return
subprocess
.
check_call
(
subprocess
.
check_call
(
command
,
shell
=
True
,
env
=
self
.
_getSubprocessEnvironment
(),
)
return
except
subprocess
.
CalledProcessError
as
e
:
if
e
.
returncode
==
SLAPGRID_PROMISE_FAIL
:
self
.
_logger
.
exception
(
'Promise error when running %s'
,
command
)
...
...
@@ -687,6 +715,7 @@ class StandaloneSlapOS(object):
retry
+=
1
def
_ensureSupervisordStarted
(
self
):
# type: () -> None
if
os
.
path
.
exists
(
self
.
_supervisor_pid
):
with
open
(
self
.
_supervisor_pid
,
'r'
)
as
f
:
try
:
...
...
@@ -715,6 +744,7 @@ class StandaloneSlapOS(object):
self
.
_logger
.
debug
(
"Started new supervisor: %s"
,
output
)
def
_isSlapOSAvailable
(
self
):
# type: () -> bool
try
:
urllib
.
request
.
urlopen
(
self
.
_master_url
).
close
()
except
urllib
.
error
.
HTTPError
as
e
:
...
...
@@ -723,6 +753,7 @@ class StandaloneSlapOS(object):
return
True
raise
except
urllib
.
error
.
URLError
as
e
:
assert
isinstance
(
e
.
reason
,
OSError
)
if
e
.
reason
.
errno
==
errno
.
ECONNREFUSED
:
return
False
raise
...
...
@@ -735,6 +766,7 @@ class StandaloneSlapOS(object):
return
True
# (if / becomes 200 OK)
def
_ensureSlapOSAvailable
(
self
):
# type: () -> None
# Wait for proxy to accept connections
for
i
in
range
(
2
**
8
):
if
self
.
_isSlapOSAvailable
():
...
...
@@ -743,12 +775,14 @@ class StandaloneSlapOS(object):
raise
RuntimeError
(
"SlapOS not started"
)
def
_getSubprocessEnvironment
(
self
):
# type: () -> Optional[Dict[str, str]]
# Running tests with `python setup.py test` sets a PYTHONPATH that
# is suitable for current python, but problematic when this process
# runs another version of python in subprocess.
if
'PYTHONPATH'
in
os
.
environ
:
self
.
_logger
.
warning
(
"Removing $PYTHONPATH from environment for subprocess"
)
"Removing $PYTHONPATH from environment for subprocess"
)
env
=
os
.
environ
.
copy
()
del
env
[
'PYTHONPATH'
]
return
env
return
None
slapos/tests/test_prune.py
View file @
656a5721
...
...
@@ -32,10 +32,11 @@ import shutil
import
unittest
import
slapos.client
try
:
import
mock
except
ImportError
:
import
sys
if
sys
.
version_info
[
0
]
==
3
:
from
unittest
import
mock
else
:
import
mock
from
slapos.cli.prune
import
do_prune
...
...
slapos/tests/test_slapproxy.py
View file @
656a5721
...
...
@@ -34,10 +34,15 @@ import os
import
logging
import
shutil
import
socket
try
:
import
subprocess32
as
subprocess
except
ImportError
:
from
typing
import
TYPE_CHECKING
if
TYPE_CHECKING
:
import
subprocess
else
:
try
:
import
subprocess32
as
subprocess
except
ImportError
:
import
subprocess
import
sys
import
tempfile
import
time
...
...
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