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
Roque
slapos.core
Commits
1bc59b59
Commit
1bc59b59
authored
Jul 03, 2023
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Plain Diff
slap/standalone: Use IPv6 range when available
See merge request
nexedi/slapos.core!538
parents
8f9a4ffd
3da9c477
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
257 additions
and
82 deletions
+257
-82
slapos/format.py
slapos/format.py
+9
-3
slapos/grid/promise/generic.py
slapos/grid/promise/generic.py
+2
-6
slapos/slap/standalone.py
slapos/slap/standalone.py
+86
-13
slapos/tests/test_cli.py
slapos/tests/test_cli.py
+1
-4
slapos/tests/test_standalone.py
slapos/tests/test_standalone.py
+144
-54
slapos/util.py
slapos/util.py
+15
-2
No files found.
slapos/format.py
View file @
1bc59b59
...
...
@@ -1464,9 +1464,15 @@ def parse_computer_definition(conf, definition_path):
address_list
.
append
(
dict
(
addr
=
address
,
netmask
=
netmask
))
if
computer_definition
.
has_option
(
section
,
'ipv6_range'
):
ipv6_range_network
=
computer_definition
.
get
(
section
,
'ipv6_range'
)
addr
,
netmask
=
ipv6_range_network
.
split
(
'/'
)
netmask
=
netmaskFromLenIPv6
(
int
(
netmask
))
ipv6_range
=
{
'addr'
:
address
,
'netmask'
:
netmask
,
'network'
:
ipv6_range_network
}
ipv6_range_addr
,
ipv6_range_prefixlen
=
ipv6_range_network
.
split
(
'/'
)
ipv6_range_prefixlen
=
int
(
ipv6_range_prefixlen
)
ipv6_range_netmask
=
netmaskFromLenIPv6
(
ipv6_range_prefixlen
)
ipv6_range
=
{
'addr'
:
ipv6_range_addr
,
'netmask'
:
ipv6_range_netmask
,
'network'
:
ipv6_range_network
,
'prefixlen'
:
ipv6_range_prefixlen
,
}
else
:
ipv6_range
=
{}
tap
=
Tap
(
computer_definition
.
get
(
section
,
'network_interface'
))
...
...
slapos/grid/promise/generic.py
View file @
1bc59b59
...
...
@@ -493,12 +493,8 @@ class GenericPromise(with_metaclass(ABCMeta, object)):
))
elif (not self.__is_tested and not check_anomaly) or
\
(not self.__is_anomaly_detected and check_anomaly):
# Anomaly or Test is disabled on this promise, send empty result
if self.getConfig('
slapgrid
-
version
', '') <= '
1.4
.
17
':
# old version cannot send EmptyResult
self.__sendResult(PromiseQueueResult(item=TestResult()))
else:
self.__sendResult(PromiseQueueResult())
# Anomaly or Test is disabled on this promise, send empty
self.__sendResult(PromiseQueueResult())
else:
try:
self.sense()
...
...
slapos/slap/standalone.py
View file @
1bc59b59
...
...
@@ -59,12 +59,25 @@ from .interface.slap import IRequester
from
..grid.slapgrid
import
SLAPGRID_PROMISE_FAIL
from
.slap
import
slap
from
..util
import
dumps
,
rmtree
from
..util
import
dumps
,
rmtree
,
getPartitionIpv6Addr
,
getPartitionIpv6Range
from
..grid.svcbackend
import
getSupervisorRPC
from
..grid.svcbackend
import
_getSupervisordSocketPath
NETMASK_IPV6_FULL
=
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
NETMASK_IPV4_FULL
=
'255.255.255.255'
def
_parseIPv6
(
ipv6
):
try
:
addr
,
prefixlen
=
ipv6
.
split
(
'/'
)
prefixlen
=
int
(
prefixlen
)
except
ValueError
:
addr
,
prefixlen
=
ipv6
,
None
return
addr
,
prefixlen
@
zope
.
interface
.
implementer
(
IException
)
class
SlapOSNodeCommandError
(
Exception
):
"""Exception raised when running a SlapOS Node command failed.
...
...
@@ -205,6 +218,7 @@ class SlapOSConfigWriter(ConfigWriter):
read_only_shared_part_list
=
'
\
n
'
.
join
(
# pylint: disable=unused-variable; used in format()
standalone_slapos
.
_shared_part_list
)
partition_forward_configuration
=
'
\
n
'
.
join
(
self
.
_getPartitionForwardConfiguration
())
has_ipv6_range
=
(
'false'
,
'true'
)[
standalone_slapos
.
_partitions_have_ipv6_range
]
with
open
(
path
,
'w'
)
as
f
:
f
.
write
(
textwrap
.
dedent
(
...
...
@@ -232,6 +246,7 @@ class SlapOSConfigWriter(ConfigWriter):
create_tap = false
create_tun = false
computer_xml = {standalone_slapos._slapos_xml}
partition_has_ipv6_range = {has_ipv6_range}
[slapproxy]
host = {standalone_slapos._server_ip}
...
...
@@ -287,9 +302,7 @@ class SlapformatDefinitionWriter(ConfigWriter):
"""
def
writeConfig
(
self
,
path
):
ipv4
=
self
.
_standalone_slapos
.
_ipv4_address
ipv6
=
self
.
_standalone_slapos
.
_ipv6_address
ipv4_cidr
=
ipv4
+
'/255.255.255.255'
if
ipv4
else
''
ipv6_cidr
=
ipv6
+
'/64'
if
ipv6
else
''
ipv4_cidr
=
'%s/%s'
%
(
ipv4
,
NETMASK_IPV4_FULL
)
if
ipv4
else
''
user
=
pwd
.
getpwuid
(
os
.
getuid
()).
pw_name
partition_base_name
=
self
.
_standalone_slapos
.
_partition_base_name
with
open
(
path
,
'w'
)
as
f
:
...
...
@@ -299,12 +312,24 @@ class SlapformatDefinitionWriter(ConfigWriter):
[computer]
address = {ipv4_cidr}
\
n
"""
).
format
(
**
locals
()))
ipv6
=
self
.
_standalone_slapos
.
_ipv6_address
for
i
in
range
(
self
.
_standalone_slapos
.
_partition_count
):
ipv6_single
,
ipv6_range
=
self
.
_standalone_slapos
.
_getPartitionIpv6
(
i
)
if
ipv6_single
:
ipv6_single_cidr
=
'%s/%s'
%
(
ipv6_single
,
NETMASK_IPV6_FULL
)
else
:
ipv6_single_cidr
=
''
if
ipv6_range
:
ipv6_range_cidr
=
'%(addr)s/%(prefixlen)s'
%
ipv6_range
ipv6_range_config_line
=
'ipv6_range = '
+
ipv6_range_cidr
else
:
ipv6_range_config_line
=
''
f
.
write
(
textwrap
.
dedent
(
"""
[partition_{i}]
address = {ipv6_cidr} {ipv4_cidr}
address = {ipv6_single_cidr} {ipv4_cidr}
{ipv6_range_config_line}
pathname = {partition_base_name}{i}
user = {user}
network_interface =
\
n
...
...
@@ -415,7 +440,13 @@ class StandaloneSlapOS(object):
self
.
_partition_base_name
=
'slappart'
self
.
_ipv4_address
=
None
self
.
_ipv6_address
=
None
self
.
_ipv6_range_prefixlen
=
None
self
.
_partitions_have_ipv6_range
=
False
# NOTE: Using Standalone's own slapos (slapos.cli.entry) instead
# is not that easy because in test nodes standalone is often run
# with gpython (pygolang), and gpython currently doesn't support
# buildout
self
.
_slapos_bin
=
slapos_bin
self
.
_slapos_commands
=
{
...
...
@@ -594,8 +625,12 @@ class StandaloneSlapOS(object):
partition_base_name
=
"slappart"
):
"""Creates `partition_count` partitions.
All partitions have the same `ipv4_address` and `ipv6_address` and
use the current system user.
All partitions have the same `ipv4_address` and use the current system
user.
`ipv6_address` can be a single address (in this case all partitions have
the same address) or a range in the form IPV6/CIDR (in this case each
partition has a subrange).
When calling this a second time with a lower `partition_count` or with
different `partition_base_name` will delete existing partitions.
...
...
@@ -628,17 +663,19 @@ class StandaloneSlapOS(object):
if
not
(
os
.
path
.
exists
(
partition_path
)):
os
.
mkdir
(
partition_path
)
os
.
chmod
(
partition_path
,
0o750
)
ipv6_addr
,
ipv6_range
=
self
.
_getPartitionIpv6
(
i
)
partition_list
.
append
({
'address_list'
:
[
{
'addr'
:
ipv4_address
,
'netmask'
:
'255.255.255.255'
'netmask'
:
NETMASK_IPV4_FULL
},
{
'addr'
:
ipv6_addr
ess
,
'netmask'
:
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
}
,
'addr'
:
ipv6_addr
,
'netmask'
:
NETMASK_IPV6_FULL
}
],
'ipv6_range'
:
ipv6_range
,
'path'
:
partition_path
,
'reference'
:
partition_reference
,
'tap'
:
{
...
...
@@ -665,7 +702,7 @@ class StandaloneSlapOS(object):
self
.
computer
.
updateConfiguration
(
dumps
({
'address'
:
ipv4_address
,
'netmask'
:
'255.255.255.255'
,
'netmask'
:
NETMASK_IPV4_FULL
,
'partition_list'
:
partition_list
,
'reference'
:
self
.
_computer_id
,
'instance_root'
:
self
.
_instance_root
,
...
...
@@ -694,11 +731,33 @@ class StandaloneSlapOS(object):
self
.
_partition_count
=
partition_count
self
.
_partition_base_name
=
partition_base_name
self
.
_ipv4_address
=
ipv4_address
self
.
_ipv6_address
=
ipv6_address
self
.
_ipv6_address
,
prefixlen
=
_parseIPv6
(
ipv6_address
)
self
.
_ipv6_range_prefixlen
=
prefixlen
self
.
_partitions_have_ipv6_range
=
bool
(
prefixlen
)
and
prefixlen
<
112
if
old_partition_count
!=
partition_count
:
SlapOSConfigWriter
(
self
).
writeConfig
(
self
.
_slapos_config
)
SlapformatDefinitionWriter
(
self
).
writeConfig
(
self
.
_slapformat_definition
)
# remove slapos xml configuration in case of ip changes
try
:
os
.
unlink
(
self
.
_slapos_xml
)
except
OSError
as
e
:
if
e
.
errno
!=
errno
.
ENOENT
:
raise
# run slapos format --now
command
=
(
self
.
_slapos_bin
,
'node'
,
'format'
,
'--now'
,
'--cfg'
,
self
.
_slapos_config
)
self
.
_logger
.
debug
(
"Running %s"
,
command
)
try
:
output
=
subprocess
.
check_output
(
command
,
stderr
=
subprocess
.
STDOUT
)
self
.
_logger
.
info
(
output
)
except
subprocess
.
CalledProcessError
as
e
:
self
.
_logger
.
error
(
e
.
output
)
raise
def
supply
(
self
,
software_url
,
computer_guid
=
None
,
state
=
"available"
):
"""Supply a software, see ISupply.supply
...
...
@@ -949,3 +1008,17 @@ class StandaloneSlapOS(object):
return
time
.
sleep
(
i
*
.
01
)
raise
RuntimeError
(
"SlapOS not started"
)
def
_getPartitionIpv6
(
self
,
i
):
# returns (single_ipv6_address, ipv6_range) for a partition
# ipv6_address can be either a range or a single IPv6 address (with no /)
prefixlen
=
self
.
_ipv6_range_prefixlen
if
prefixlen
is
None
:
return
self
.
_ipv6_address
,
None
ipv6_range
=
{
'addr'
:
self
.
_ipv6_address
,
'prefixlen'
:
prefixlen
}
ipv6_single
=
getPartitionIpv6Addr
(
ipv6_range
,
i
)[
'addr'
]
if
self
.
_partitions_have_ipv6_range
:
ipv6_partition_range
=
getPartitionIpv6Range
(
ipv6_range
,
i
,
16
)
return
ipv6_single
,
ipv6_partition_range
else
:
return
ipv6_single
,
None
slapos/tests/test_cli.py
View file @
1bc59b59
...
...
@@ -442,16 +442,13 @@ class TestCliBoot(CliMixin):
patch
(
'slapos.cli.boot.ConfigCommand.config_path'
,
return_value
=
slapos_conf
.
name
),
\
patch
(
'slapos.cli.boot.netifaces.ifaddresses'
,
return_value
=
{
socket
.
AF_INET6
:
({
'addr'
:
'2000::1'
},),},)
as
ifaddresses
,
\
patch
(
'slapos.cli.boot._ping_hostname'
,
return_value
=
1
)
as
_ping_hostname
:
return_value
=
{
socket
.
AF_INET6
:
({
'addr'
:
'2000::1'
},),},)
as
ifaddresses
:
app
.
run
((
'node'
,
'boot'
))
# boot command runs as root
check_root_user
.
assert_called_once
()
# it waits for interface to have an IPv6 address
ifaddresses
.
assert_called_once_with
(
'interface_name_from_config'
)
# then ping master hostname to wait for connectivity
_ping_hostname
.
assert_called_once_with
(
'slap.vifib.com'
)
# then format and bang
SlapOSApp
().
run
.
assert_any_call
([
'node'
,
'format'
,
'--now'
,
'--verbose'
])
SlapOSApp
().
run
.
assert_any_call
([
'node'
,
'bang'
,
'-m'
,
'Reboot'
])
...
...
slapos/tests/test_standalone.py
View file @
1bc59b59
This diff is collapsed.
Click to expand it.
slapos/util.py
View file @
1bc59b59
...
...
@@ -38,6 +38,7 @@ import socket
import
sqlite3
import
struct
import
subprocess
import
sys
import
warnings
import
jsonschema
...
...
@@ -201,7 +202,7 @@ def ipv6FromBin(ip, suffix=''):
if
suffix_len
>
0
:
ip
+=
suffix
.
rjust
(
suffix_len
,
'0'
)
elif
suffix_len
:
sys
.
exit
(
"Prefix
exceeds 128 bits"
)
sys
.
exit
(
"Prefix
%s exceeds 128 bits by %d bit"
%
(
ip
,
-
suffix_len
)
)
return
socket
.
inet_ntop
(
socket
.
AF_INET6
,
struct
.
pack
(
'>QQ'
,
int
(
ip
[:
64
],
2
),
int
(
ip
[
64
:],
2
)))
...
...
@@ -214,11 +215,23 @@ def getPartitionIpv6Addr(ipv6_range, partition_index):
}
returns the IPv6 addr
addr::(partition_index+2) (address 1 is is used by re6st)
If the range is too small, wrap around
"""
addr
=
ipv6_range
[
'addr'
]
prefixlen
=
ipv6_range
[
'prefixlen'
]
prefix
=
binFromIpv6
(
addr
)[:
prefixlen
]
return
dict
(
addr
=
ipv6FromBin
(
prefix
+
bin
(
partition_index
+
2
)[
2
:].
zfill
(
128
-
prefixlen
)),
prefixlen
=
prefixlen
)
remaining
=
128
-
prefixlen
suffix
=
bin
(
partition_index
+
2
)[
2
:]
if
len
(
suffix
)
>
remaining
:
if
remaining
>=
2
:
# skip reserved addresses 0 and 1
suffix
=
bin
((
partition_index
%
((
1
<<
remaining
)
-
2
))
+
2
)[
2
:]
else
:
# truncate, we have no other addresses than 0 and 1
suffix
=
suffix
[
len
(
suffix
)
-
remaining
:]
suffix
=
suffix
.
zfill
(
remaining
)
bits
=
prefix
+
suffix
return
dict
(
addr
=
ipv6FromBin
(
bits
),
prefixlen
=
prefixlen
)
def
getIpv6RangeFactory
(
k
,
s
):
"""
...
...
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