Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
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
Xavier Thompson
erp5
Commits
c8d33446
Commit
c8d33446
authored
Aug 24, 2017
by
Roque
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
All my changes since beginning. Includes tasks: 1 to 4 (done) and 5 (current).
parent
646852df
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
666 additions
and
246 deletions
+666
-246
erp5/util/testnode/ScalabilityTestRunner.py
erp5/util/testnode/ScalabilityTestRunner.py
+128
-31
erp5/util/testnode/SlapOSControler.py
erp5/util/testnode/SlapOSControler.py
+16
-5
erp5/util/testnode/SlapOSMasterCommunicator.py
erp5/util/testnode/SlapOSMasterCommunicator.py
+513
-207
erp5/util/testnode/testnode.py
erp5/util/testnode/testnode.py
+9
-3
No files found.
erp5/util/testnode/ScalabilityTestRunner.py
View file @
c8d33446
...
...
@@ -24,9 +24,6 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
############## ROQUE VERSION #################################################
import
datetime
import
os
import
subprocess
...
...
@@ -49,6 +46,10 @@ from erp5.util import taskdistribution
# for dummy slapos answer
import
signal
import
slapos.slap
# max time to instance changing state: 2 hour
MAX_INSTANCE_TIME
=
60
*
60
*
2
# max time to register instance to slapOSMaster: 5 minutes
...
...
@@ -68,7 +69,6 @@ class ScalabilityTestRunner():
# Create the slapos account configuration file and dir
key
=
self
.
testnode
.
test_suite_portal
.
getSlaposAccountKey
()
certificate
=
self
.
testnode
.
test_suite_portal
.
getSlaposAccountCertificate
()
# Get Slapos Master Url
self
.
slapos_url
=
''
try
:
...
...
@@ -85,7 +85,7 @@ class ScalabilityTestRunner():
self
.
log
(
"SlapOS Master hateoas url is: %s"
%
self
.
slapos_api_rest_url
)
self
.
key_path
,
self
.
cert_path
,
config_path
=
self
.
slapos_controler
.
createSlaposConfigurationFileAccount
(
key
,
certificate
,
self
.
slapos_url
,
self
.
testnode
.
config
)
key
,
certificate
,
self
.
slapos_url
,
self
.
testnode
.
config
,
self
.
slapos_api_rest_url
)
self
.
slapos_communicator
=
None
# Dict containing used to store which SR is not yet correctly installed.
# looks like: {'comp_id1':'SR_urlA', 'comp_id2':'SR_urlA',..}
...
...
@@ -106,7 +106,9 @@ class ScalabilityTestRunner():
self
.
log
(
"testnode, supply : %s %s"
,
software_path
,
computer_guid
)
if
self
.
authorize_supply
:
self
.
remaining_software_installation_dict
[
computer_guid
]
=
software_path
self
.
slapos_controler
.
supply
(
software_path
,
computer_guid
)
#self.slapos_controler.supply(software_path, computer_guid)
#self.slapos_communicator._supply("available")
# Here make a request via slapos controler ?
return
{
'status_code'
:
0
}
else
:
...
...
@@ -150,9 +152,21 @@ class ScalabilityTestRunner():
test_result
,
test_suite
)
self
.
log
(
"testnode, request : %s"
,
instance_title
)
config
=
json
.
dumps
(
config
)
self
.
slapos_controler
.
request
(
instance_title
,
software_path
,
"test"
,
{
"_"
:
config
},
self
.
launcher_nodes_computer_guid
[
0
])
#request_kw = {"_" : config}
request
=
{
"_"
:
config
}
request_kw
=
{
"partition_parameter_kw"
:
request
}
#self.log("config from softConf, tResult & tSuite: " + str(config))
#self.log("request_kw: " + str(request_kw))
self
.
log
(
"Computer : "
+
str
(
self
.
launcher_nodes_computer_guid
[
0
]))
#self.slapos_controler.request(instance_title, software_path,
# "test", {"_" : config},
# self.launcher_nodes_computer_guid[0])
self
.
slapos_communicator
.
setName
(
instance_title
)
self
.
slapos_communicator
.
setRequestParameters
(
request_kw
)
# ROQUE: request commented because it's failing. Instance manually requested.
#self.slapos_communicator._request("started")
# ROQUE: harcoded state (that should happens in the ._request )
self
.
slapos_communicator
.
forceSetState
(
'started'
)
self
.
authorize_request
=
False
return
{
'status_code'
:
0
}
else
:
...
...
@@ -224,9 +238,11 @@ late a SlapOS (positive) answer." %(str(os.getpid()),str(os.getpid()),))
"""
Wait for 'max_time' an instance specific state
"""
max_time
=
20
self
.
log
(
"Wait for instance state: %s"
%
state
)
start_time
=
time
.
time
()
while
(
not
self
.
slapos_communicator
.
isHostingSubscriptionReady
(
instance_title
,
state
)
#while (not self.slapos_communicator.isHostingSubscriptionReady(instance_title, state)
while
(
not
self
.
slapos_communicator
.
_getInstanceState
()
==
state
and
(
max_time
>
(
time
.
time
()
-
start_time
))):
self
.
log
(
"Instance(s) not in %s state yet."
%
state
)
time
.
sleep
(
15
)
...
...
@@ -243,13 +259,17 @@ late a SlapOS (positive) answer." %(str(os.getpid()),str(os.getpid()),))
raise
ValueError
(
error_message
)
self
.
log
(
"Instance correctly '%s' after %s seconds."
%
(
state
,
str
(
time
.
time
()
-
start_time
)))
def
_waitInstanceCreation
(
self
,
instance_title
,
max_time
=
MAX_CREATION_INSTANCE_TIME
):
def
_waitInstanceCreation
(
self
,
instance_title
,
hateoas
,
max_time
=
MAX_CREATION_INSTANCE_TIME
):
"""
Wait for 'max_time' the instance creation
"""
self
.
log
(
"Wait
for instance creation
"
)
self
.
log
(
"Wait
ing for instance creation...
"
)
start_time
=
time
.
time
()
while
(
not
self
.
slapos_communicator
.
isRegisteredHostingSubscription
(
instance_title
)
\
#while ( not self.slapos_communicator.isRegisteredHostingSubscription(instance_title) \
self
.
log
(
"Instance title: "
+
str
(
instance_title
))
#self.log("List of Hosting subscriptions : ")
#self.log(str(hateoas.getHostingSubscriptionDict()))
while
(
not
instance_title
in
hateoas
.
getHostingSubscriptionDict
()
\
and
(
max_time
>
(
time
.
time
()
-
start_time
))
):
time
.
sleep
(
5
)
if
(
time
.
time
()
-
start_time
)
>
max_time
:
...
...
@@ -260,18 +280,52 @@ late a SlapOS (positive) answer." %(str(os.getpid()),str(os.getpid()),))
"""
Install testsuite softwares
"""
self
.
log
(
'
prepareSlapOSForTestSuite
'
)
self
.
log
(
'
Preparing SlapOS for Test Suite...
'
)
# Define how many time this method can take
max_time
=
3600
*
10
*
1.0
# 10 hours
interval_time
=
60
start_time
=
time
.
time
()
# Create a communicator with slapos
self
.
log
(
"creating SlapOs Master communicator..."
)
self
.
slapos_communicator
=
SlapOSMasterCommunicator
.
SlapOSMasterCommunicator
(
self
.
cert_path
,
self
.
key_path
,
self
.
log
,
self
.
slapos_api_rest_url
)
#self.log("CERT: " + str(self.cert_path))
#self.log("KEY: " + str(self.key_path))
#self.log("API URL: " + str(self.slapos_api_rest_url))
#self.log("MASTER URL: " + str(self.slapos_url))
### NEW ! Creating Slapos master communicator ###
slap
=
slapos
.
slap
.
slap
()
retry
=
0
while
True
:
if
retry
>
100
:
break
# wait until _hateoas_navigator is loaded.
slap
.
initializeConnection
(
self
.
slapos_url
,
self
.
key_path
,
self
.
cert_path
,
timeout
=
120
,
slapgrid_rest_uri
=
self
.
slapos_api_rest_url
)
if
getattr
(
slap
,
'_hateoas_navigator'
,
None
)
is
None
:
retry
+=
1
self
.
log
(
"Fail to load _hateoas_navigator waiting a bit and retry."
)
time
.
sleep
(
30
)
else
:
break
if
getattr
(
slap
,
'_hateoas_navigator'
,
None
)
is
None
:
raise
ValueError
(
"Fail to load _hateoas_navigator"
)
hateoas
=
getattr
(
slap
,
'_hateoas_navigator'
,
None
)
#self.log("_hateoas_navigator object ")
#self.log(".getHostingSubscriptionDict()")
#self.log(hateoas.getHostingSubscriptionDict())
#self.log("_hateoasGetInformation()")
#self.log(hateoas._hateoasGetInformation("nxdcloud-onlinenet-scalabilitynode-001-ERP5SCALABILITY"))
#self.log("getHostingSubscriptionRootSoftwareInstanceInformation(node)")
#self.log(hateoas.getHostingSubscriptionRootSoftwareInstanceInformation("nxdcloud-onlinenet-scalabilitynode-001-ERP5SCALABILITY"))
#self.log(".getRelatedInstanceInformation(node)")
#self.log(hateoas.getRelatedInstanceInformation("nxdcloud-onlinenet-scalabilitynode-001-ERP5SCALABILITY"))
supply
=
slap
.
registerSupply
()
order
=
slap
.
registerOpenOrder
()
### //NEW ! ###
# Only master testnode must order software installation
if
self
.
testnode
.
test_suite_portal
.
isMasterTestnode
(
self
.
testnode
.
config
[
'test_node_title'
]):
...
...
@@ -340,7 +394,9 @@ late a SlapOS (positive) answer." %(str(os.getpid()),str(os.getpid()),))
# Ask for SR installation
for
computer_guid
in
self
.
involved_nodes_computer_guid
:
self
.
_prepareSlapOS
(
self
.
reachable_profile
,
computer_guid
)
self
.
slapos_communicator
=
SlapOSMasterCommunicator
.
SoftwareReleaseTester
(
"NAME"
,
self
.
log
,
slap
,
supply
,
order
,
self
.
reachable_profile
,
computer_guid
=
computer_guid
)
# ROQUE: "_prepareSlapOS" is commented because the instance request is not working (manually created for dev purposes)
#self._prepareSlapOS(self.reachable_profile, computer_guid)
# From the line below we would not supply any more softwares
self
.
authorize_supply
=
False
# TODO : remove the line below wich simulate an answer from slapos master
...
...
@@ -362,14 +418,49 @@ late a SlapOS (positive) answer." %(str(os.getpid()),str(os.getpid()),))
# Launch instance
self
.
instance_title
=
self
.
_generateInstanceTitle
(
node_test_suite
.
test_suite_title
)
try
:
# ROQUE: the instance title is harcoded because the instance request is not working (this one was manually created)
self
.
instance_title
=
"nxdcloud-onlinenet-scalabilitynode-001-TESTINSTANCE"
self
.
_createInstance
(
self
.
reachable_profile
,
configuration_list
[
0
],
self
.
instance_title
,
node_test_suite
.
test_result
,
node_test_suite
.
test_suite
)
self
.
log
(
"Scalability instance requested."
)
except
:
self
.
log
(
"Unable to launch instance"
)
raise
ValueError
(
"Unable to launch instance"
)
self
.
log
(
"Waiting for instance creation.."
)
self
.
_waitInstanceCreation
(
self
.
instance_title
)
self
.
_waitInstanceCreation
(
self
.
instance_title
,
hateoas
)
computer
=
self
.
slapos_communicator
.
_hateoas_getComputer
(
"COMP-2732"
)
#self.log("COMPUTER: " + str(computer))
#software_installation_list = self.slapos_communicator.getSoftwareInstallationList()
#self.log("software_installation_list: ")
#self.log(str(software_installation_list))
getSoftwareInstallationNews
=
self
.
slapos_communicator
.
getSoftwareInstallationNews
()
self
.
log
(
"Software installation news: "
)
self
.
log
(
str
(
getSoftwareInstallationNews
))
#getInstanceUrlList = self.slapos_communicator.getInstanceUrlList()
#self.log("getInstanceUrlList")
#self.log(str(getInstanceUrlList))
# ROQUE: for debugging purposes
instance_url
=
'https://api.vifib.com/software_instance_module/20170822-1568166F/ERP5Document_getHateoas'
self
.
log
(
"getNewsFromInstance(url)"
)
self
.
log
(
str
(
self
.
slapos_communicator
.
getNewsFromInstance
(
instance_url
)))
self
.
log
(
"getInformationFromInstance(url)"
)
self
.
log
(
str
(
self
.
slapos_communicator
.
getInformationFromInstance
(
instance_url
)))
# ROQUE: get info contains the software release url
#getInfo = self.slapos_communicator.getInfo()
#self.log("getInfo: ")
#self.log(str(getInfo))
# "No message"
#getFormatedLastMessage = self.slapos_communicator.getFormatedLastMessage()
#self.log("getFormatedLastMessage: ")
#self.log(str(getFormatedLastMessage))
getSoftwareState
=
self
.
slapos_communicator
.
_getSoftwareState
()
self
.
log
(
"Software state: "
+
str
(
getSoftwareState
))
getInstanceState
=
self
.
slapos_communicator
.
_getInstanceState
()
self
.
log
(
"Instance state: "
+
str
(
getInstanceState
))
return
{
'status_code'
:
0
}
return
{
'status_code'
:
1
}
...
...
@@ -380,17 +471,21 @@ late a SlapOS (positive) answer." %(str(os.getpid()),str(os.getpid()),))
configuration_list
=
node_test_suite
.
configuration_list
test_list
=
range
(
0
,
len
(
configuration_list
))
# create test_result
self
.
log
(
"Creating Test Result..."
)
test_result_proxy
=
self
.
testnode
.
portal
.
createTestResult
(
node_test_suite
.
revision
,
test_list
,
self
.
testnode
.
config
[
'test_node_title'
],
True
,
node_test_suite
.
test_suite_title
,
node_test_suite
.
project_title
)
self
.
log
(
"Test Result created."
)
count
=
0
error_message
=
None
# Each cluster configuration are tested
self
.
log
(
"FOR CONFIG IN CONFIG_LIST:"
)
for
configuration
in
configuration_list
:
self
.
log
(
"configuration n: "
+
str
(
count
))
self
.
log
(
str
(
configuration
))
# First configuration doesn't need XML configuration update.
if
count
>
0
:
...
...
@@ -400,19 +495,21 @@ late a SlapOS (positive) answer." %(str(os.getpid()),str(os.getpid()),))
# Update instance XML configuration
self
.
_updateInstanceXML
(
configuration
,
self
.
instance_title
,
node_test_suite
.
test_result
,
node_test_suite
.
test_suite
)
self
.
_waitInstance
(
self
.
instance_title
,
'started'
)
self
.
_waitInstance
(
self
.
instance_title
,
SlapOSMasterCommunicator
.
INSTANCE_STATE_STARTED
)
# Start instance
self
.
slapos_controler
.
startInstance
(
self
.
instance_title
)
# XXX: Dirty hack used to force haproxy to restart in time
# with all zope informations.
self
.
_waitInstance
(
self
.
instance_title
,
'started'
)
self
.
slapos_controler
.
stopInstance
(
self
.
instance_title
)
self
.
_waitInstance
(
self
.
instance_title
,
'stopped'
)
self
.
slapos_controler
.
startInstance
(
self
.
instance_title
)
self
.
_waitInstance
(
self
.
instance_title
,
SlapOSMasterCommunicator
.
INSTANCE_STATE_STARTED
)
#self.slapos_controler.stopInstance(self.instance_title)
self
.
slapos_communicator
.
_request
(
'stopped'
)
self
.
_waitInstance
(
self
.
instance_title
,
SlapOSMasterCommunicator
.
INSTANCE_STATE_STOPPED
)
self
.
slapos_communicator
.
_request
(
'started'
)
#self.slapos_controler.startInstance(self.instance_title)
##########################################################
self
.
_waitInstance
(
self
.
instance_title
,
'started'
)
self
.
_waitInstance
(
self
.
instance_title
,
SlapOSMasterCommunicator
.
INSTANCE_STATE_STARTED
)
# Start only the current test
exclude_list
=
[
x
for
x
in
test_list
if
x
!=
test_list
[
count
]]
...
...
erp5/util/testnode/SlapOSControler.py
View file @
c8d33446
...
...
@@ -37,6 +37,8 @@ import argparse
import
json
from
slapos
import
client
from
ConfigParser
import
ConfigParser
MAX_PARTIONS
=
10
MAX_SR_RETRIES
=
3
...
...
@@ -78,7 +80,7 @@ class SlapOSControler(object):
#TODO: implement a method to get all instance related the slapOS account
# and deleting all old instances (based on creation date or name etc...)
def
createSlaposConfigurationFileAccount
(
self
,
key
,
certificate
,
slapos_url
,
config
):
def
createSlaposConfigurationFileAccount
(
self
,
key
,
certificate
,
slapos_url
,
config
,
slapos_rest_url
):
# Create "slapos_account" directory in the "slapos_directory"
slapos_account_directory
=
os
.
path
.
join
(
config
[
'slapos_directory'
],
"slapos_account"
)
createFolder
(
slapos_account_directory
)
...
...
@@ -86,9 +88,10 @@ class SlapOSControler(object):
slapos_account_key_path
=
os
.
path
.
join
(
slapos_account_directory
,
"key"
)
slapos_account_certificate_path
=
os
.
path
.
join
(
slapos_account_directory
,
"certificate"
)
configuration_file_path
=
os
.
path
.
join
(
slapos_account_directory
,
"slapos.cfg"
)
configuration_file_value
=
"[slapos]
\
n
master_url = %s
\
n
\
configuration_file_value
=
"[slapos]
\
n
master_url = %s
\
n
master_rest_url = %s
\
n
\
[slapconsole]
\
n
cert_file = %s
\
n
key_file = %s"
%
(
slapos_url
,
slapos_rest_url
,
slapos_account_certificate_path
,
slapos_account_key_path
)
createFile
(
slapos_account_key_path
,
"w"
,
key
)
...
...
@@ -109,11 +112,19 @@ class SlapOSControler(object):
parser
.
add_argument
(
"software_url"
)
parser
.
add_argument
(
"node"
)
if
os
.
path
.
exists
(
self
.
configuration_file_path
):
self
.
log
(
"configuration_file_path: "
+
str
(
self
.
configuration_file_path
))
args
=
parser
.
parse_args
([
self
.
configuration_file_path
,
software_url
,
computer_id
])
config
=
client
.
Config
()
config
.
setConfig
(
args
,
args
.
configuration_file
)
self
.
log
(
"parsed args: "
+
str
(
args
))
#config = client.Config()
#config.setConfig(args, args.configuration_file)
self
.
log
(
"Creating clientConfig..."
)
configp
=
ConfigParser
()
configp
.
read
(
self
.
configuration_file_path
)
config
=
client
.
ClientConfig
(
args
,
configp
)
try
:
local
=
client
.
init
(
config
)
self
.
log
(
"config instantiated. Calling client.init(config)..."
)
local
=
client
.
init
(
config
,
self
.
log
)
self
.
log
(
"local instantiated with client.init!"
)
local
[
'supply'
](
software_url
,
computer_guid
=
computer_id
,
state
=
state
)
self
.
log
(
'SlapOSControler : supply %s %s %s'
%
(
software_url
,
computer_id
,
state
))
except
:
...
...
erp5/util/testnode/SlapOSMasterCommunicator.py
View file @
c8d33446
import
datetime
import
json
import
httplib
import
urlparse
import
sys
import
traceback
import
time
#import feedparser
from
uritemplate
import
expand
TIMEOUT
=
30
import
slapos.slap
from
slapos.slap
import
SoftwareProductCollection
from
slapos.slap.slap
import
ConnectionError
from
requests.exceptions
import
HTTPError
from
erp5.util.taskdistribution
import
SAFE_RPC_EXCEPTION_LIST
SOFTWARE_PRODUCT_NAMESPACE
=
"product."
SOFTWARE_STATE_UNKNOWN
=
"SOFTWARE_STATE_UNKNOWN"
SOFTWARE_STATE_INSTALLING
=
"SOFTWARE_STATE_INSTALLING"
SOFTWARE_STATE_INSTALLED
=
"SOFTWARE_STATE_INSTALLED"
SOFTWARE_STATE_DESTROYING
=
"SOFTWARE_STATE_DESTROYING"
INSTANCE_STATE_UNKNOWN
=
"INSTANCE_STATE_UNKNOWN"
INSTANCE_STATE_STARTING
=
"INSTANCE_STATE_STARTING"
INSTANCE_STATE_STARTED
=
"INSTANCE_STATE_STARTED"
INSTANCE_STATE_STARTED_WITH_ERROR
=
"INSTANCE_STATE_STARTED_WITH_ERROR"
INSTANCE_STATE_STOPPING
=
"INSTANCE_STATE_STOPPING"
INSTANCE_STATE_STOPPED
=
"INSTANCE_STATE_STOPPED"
INSTANCE_STATE_DESTROYING
=
"INSTANCE_STATE_DESTROYING"
TESTER_STATE_INITIAL
=
"TESTER_STATE_INITIAL"
TESTER_STATE_NOTHING
=
"TESTER_STATE_NOTHING"
TESTER_STATE_SOFTWARE_INSTALLED
=
"TESTER_STATE_SOFTWARE_INSTALLED"
TESTER_STATE_INSTANCE_INSTALLED
=
"TESTER_STATE_INSTANCE_INSTALLED"
TESTER_STATE_INSTANCE_STARTED
=
"TESTER_STATE_INSTANCE_STARTED"
TESTER_STATE_INSTANCE_UNINSTALLED
=
"TESTER_STATE_INSTANCE_UNINSTALLED"
# Simple decorator to prevent raise due small
# network failures.
def
retryOnNetworkFailure
(
func
):
def
wrapper
(
*
args
,
**
kwargs
):
retry_time
=
64
while
True
:
try
:
return
func
(
*
args
,
**
kwargs
)
except
SAFE_RPC_EXCEPTION_LIST
,
e
:
print
'Network failure: %s , %s'
%
(
sys
.
exc_info
(),
e
)
except
HTTPError
,
e
:
print
'Network failure: %s , %s'
%
(
sys
.
exc_info
(),
e
)
except
ConnectionError
,
e
:
print
'Network failure: %s , %s'
%
(
sys
.
exc_info
(),
e
)
except
slapos
.
slap
.
ConnectionError
,
e
:
print
'Network failure: %s , %s'
%
(
sys
.
exc_info
(),
e
)
print
'Retry method %s in %i seconds'
%
(
func
,
retry_time
)
time
.
sleep
(
retry_time
)
retry_time
=
min
(
retry_time
*
1.5
,
640
)
wrapper
.
__name__
=
func
.
__name__
wrapper
.
__doc__
=
func
.
__doc__
return
wrapper
# TODO: News-> look list to get last news... (and not the first of the list)
class
SlapOSMasterCommunicator
(
object
):
"""
Communication with slapos Master using Hateoas.
collection: collection of data (hosting_subscription, instance, software_release...)
hosting_subscription: result of a request
instance(s): instance(s) related to an hosting_subscription
usage: ex:
# Try to reuse same communicator, because initilization step may takes a lot of time
# due to listing of all instances (alive or not) related to the specified slapOS account.
communicator = SlapOSMasterCommunicator()
# Print news related to 'TestScalability_21423104630420' all instances
instance_link_list = communicator._getRelatedInstanceLink('TestScalability_21423104630420')
for instance_link in instance_link_list:
news = communicator.getNewsFromInstanceLink(instance_link)
print news['news']
"""
def
__init__
(
self
,
certificate_path
,
key_path
,
log
,
url
):
# Create connection
api_scheme
,
api_netloc
,
api_path
,
api_query
,
api_fragment
=
urlparse
.
urlsplit
(
url
)
self
.
log
=
log
self
.
certificate_path
=
certificate_path
self
.
key_path
=
key_path
def
__init__
(
self
,
slap
,
slap_supply
,
slap_order
,
url
,
logger
):
self
.
_logger
=
logger
self
.
slap
=
slap
self
.
slap_order
=
slap_order
self
.
slap_supply
=
slap_supply
self
.
hateoas_navigator
=
self
.
slap
.
_hateoas_navigator
self
.
hosting_subscription_url
=
None
#self.computer_guid = computer_guid
#self.name = name
if
url
is
not
None
and
\
url
.
startswith
(
SOFTWARE_PRODUCT_NAMESPACE
):
product
=
SoftwareProductCollection
(
self
.
_logger
,
self
.
slap
)
try
:
url
=
product
.
__getattr__
(
url
[
len
(
SOFTWARE_PRODUCT_NAMESPACE
):])
except
AttributeError
as
e
:
self
.
_logger
.
warning
(
'Error on get software release : %s '
%
e
.
message
)
self
.
url
=
url
self
.
log
(
"Getting connection to "
+
str
(
self
.
url
))
self
.
connection
=
self
.
_getConnection
(
self
.
certificate_path
,
self
.
key_path
,
self
.
url
)
self
.
log
(
"Connection done."
)
# Get master
master_link
=
{
'href'
:
api_path
,
'type'
:
"application/vnd.slapos.org.hal+json; class=slapos.org.master"
}
self
.
log
(
"Getting master with href: "
+
str
(
api_path
))
#master = self._curl(master_link)
#self.person_link = master['_links']['http://slapos.org/reg/me']
self
.
person_link
=
{
"href"
:
"urn:jio:get:person_module/20170705-995F2E"
}
self
.
log
(
"Getting person with curl to harcoded link."
)
# Get person related to specified key/certificate provided
person
=
self
.
_curl
(
self
.
person_link
)
self
.
log
(
"person: "
str
(
person
))
self
.
personnal_collection_link
=
person
[
'_links'
][
'http://slapos.org/reg/hosting_subscription'
]
self
.
log
(
"personal collection link : "
+
str
(
self
.
personnal_collection_link
))
# Get collection (of hosting subscriptions)
self
.
log
(
"Getting collection with curl"
)
collection
=
self
.
_curl
(
self
.
personnal_collection_link
)
self
.
log
(
"collection: "
+
str
(
collection
))
# XXX: This part may be extremly long (because here no hosting subscriptions
# has been visited)
self
.
hosting_subcriptions_dict
=
{}
self
.
visited_hosting_subcriptions_link_list
=
[]
self
.
log
(
"SlapOSMasterCommunicator will read all hosting subscriptions entries, "
"it may take several time..."
)
self
.
_update_hosting_subscription_informations
()
def
_getConnection
(
self
,
certificate_path
,
key_path
,
url
):
api_scheme
,
api_netloc
,
api_path
,
api_query
,
api_fragment
=
urlparse
.
urlsplit
(
url
)
#self.log("HTTPS Connection with: api_scheme=%s, api_netloc=%s, api_path=%s, api_query=%s, api_fragment=%s" %(api_scheme, api_netloc, api_path, api_query, api_fragment))
self
.
log
(
"_getConnection method - api_netloc: "
+
str
(
api_netloc
))
return
httplib
.
HTTPSConnection
(
api_netloc
,
key_file
=
key_path
,
cert_file
=
certificate_path
,
timeout
=
TIMEOUT
)
def
_curl
(
self
,
link
):
"""
'link' must look like : {'href':url,'type':content_type}
"""
# Set timeout
import
socket
socket
.
setdefaulttimeout
(
1.0
*
TIMEOUT
)
api_scheme
,
api_netloc
,
api_path
,
api_query
,
api_fragment
=
urlparse
.
urlsplit
(
link
[
'href'
])
max_retry
=
10
# Try to use existing conection
def
setName
(
self
,
name
):
self
.
name
=
name
def
setRequestParameters
(
self
,
request_kw
):
if
isinstance
(
request_kw
,
str
)
or
\
isinstance
(
request_kw
,
unicode
):
self
.
request_kw
=
json
.
loads
(
request_kw
)
else
:
self
.
request_kw
=
request_kw
#self._logger("request parameters set: " + str(self.request_kw))
@
retryOnNetworkFailure
def
_supply
(
self
,
state
):
if
self
.
computer_guid
is
None
:
self
.
_logger
.
log
(
'Nothing to supply for %s.'
%
(
self
.
name
))
return
None
self
.
_logger
(
"From SlapOSMasterCommunicator"
)
self
.
_logger
(
'Supply %s@%s: %s'
,
self
.
url
,
self
.
computer_guid
,
state
)
return
self
.
slap_supply
.
supply
(
self
.
url
,
self
.
computer_guid
)
#return self.slap_supply.supply(self.url, self.computer_guid, state)
@
retryOnNetworkFailure
def
_request
(
self
,
state
):
self
.
_logger
.
info
(
'Request %s@%s: %s'
,
self
.
url
,
self
.
name
,
state
)
self
.
latest_state
=
state
return
self
.
slap_order
.
request
(
software_release
=
self
.
url
,
partition_reference
=
self
.
name
,
state
=
state
,
**
self
.
request_kw
)
@
retryOnNetworkFailure
def
_hateoas_getComputer
(
self
,
reference
):
root_document
=
self
.
hateoas_navigator
.
getRootDocument
()
search_url
=
root_document
[
"_links"
][
'raw_search'
][
'href'
]
getter_link
=
expand
(
search_url
,
{
"query"
:
"reference:%s AND portal_type:Computer"
%
reference
,
"select_list"
:
[
"relative_url"
],
"limit"
:
1
})
result
=
self
.
hateoas_navigator
.
GET
(
getter_link
)
content_list
=
json
.
loads
(
result
)[
'_embedded'
][
'contents'
]
if
len
(
content_list
)
==
0
:
raise
Exception
(
'No Computer found.'
)
computer_relative_url
=
content_list
[
0
][
"relative_url"
]
getter_url
=
self
.
hateoas_navigator
.
getDocumentAndHateoas
(
computer_relative_url
)
return
json
.
loads
(
self
.
hateoas_navigator
.
GET
(
getter_url
))
@
retryOnNetworkFailure
def
getSoftwareInstallationList
(
self
):
# XXX Move me to slap.py API
computer
=
self
.
_hateoas_getComputer
(
self
.
computer_guid
)
# Not a list ?
action
=
computer
[
'_links'
][
'action_object_slap'
]
if
action
.
get
(
'title'
)
==
'getHateoasSoftwareInstallationList'
:
getter_link
=
action
[
'href'
]
else
:
raise
Exception
(
'No Link found found.'
)
result
=
self
.
hateoas_navigator
.
GET
(
getter_link
)
return
json
.
loads
(
result
)[
'_links'
][
'content'
]
@
retryOnNetworkFailure
def
getSoftwareInstallationNews
(
self
):
getter_link
=
None
for
si
in
self
.
getSoftwareInstallationList
():
if
si
[
"title"
]
==
self
.
url
:
getter_link
=
si
[
"href"
]
break
# We could not find the document, so it is probably too soon.
if
getter_link
is
None
:
return
""
result
=
self
.
hateoas_navigator
.
GET
(
getter_link
)
action_object_slap_list
=
json
.
loads
(
result
)[
'_links'
][
'action_object_slap'
]
for
action
in
action_object_slap_list
:
if
action
.
get
(
'title'
)
==
'getHateoasNews'
:
getter_link
=
action
[
'href'
]
break
else
:
raise
Exception
(
'getHateoasNews not found.'
)
result
=
self
.
hateoas_navigator
.
GET
(
getter_link
)
if
len
(
json
.
loads
(
result
)[
'news'
])
>
0
:
return
json
.
loads
(
result
)[
'news'
][
0
][
"text"
]
return
""
@
retryOnNetworkFailure
def
getInstanceUrlList
(
self
):
if
self
.
hosting_subscription_url
is
None
:
hosting_subscription_dict
=
self
.
hateoas_navigator
.
_hateoas_getHostingSubscriptionDict
()
for
hs
in
hosting_subscription_dict
:
if
hs
[
'title'
]
==
self
.
name
:
self
.
hosting_subscription_url
=
hs
[
'href'
]
break
if
self
.
hosting_subscription_url
is
None
:
return
None
return
self
.
hateoas_navigator
.
getHateoasInstanceList
(
self
.
hosting_subscription_url
)
@
retryOnNetworkFailure
def
getNewsFromInstance
(
self
,
url
):
result
=
self
.
hateoas_navigator
.
GET
(
url
)
result
=
json
.
loads
(
result
)
if
result
[
'_links'
].
get
(
'action_object_slap'
,
None
)
is
None
:
return
None
object_link
=
self
.
hateoas_navigator
.
hateoasGetLinkFromLinks
(
result
[
'_links'
][
'action_object_slap'
],
'getHateoasNews'
)
result
=
self
.
hateoas_navigator
.
GET
(
object_link
)
return
json
.
loads
(
result
)[
'news'
]
@
retryOnNetworkFailure
def
getInformationFromInstance
(
self
,
url
):
result
=
self
.
hateoas_navigator
.
GET
(
url
)
result
=
json
.
loads
(
result
)
if
result
[
'_links'
].
get
(
'action_object_slap'
,
None
)
is
None
:
print
result
[
'links'
]
return
None
object_link
=
self
.
hateoas_navigator
.
hateoasGetLinkFromLinks
(
result
[
'_links'
][
'action_object_slap'
],
'getHateoasInformation'
)
result
=
self
.
hateoas_navigator
.
GET
(
object_link
)
return
json
.
loads
(
result
)
class
SoftwareReleaseTester
(
SlapOSMasterCommunicator
):
deadline
=
None
latest_state
=
None
def
__init__
(
self
,
name
,
logger
,
slap
,
slap_order
,
slap_supply
,
url
,
# software release url
computer_guid
=
None
,
# computer for supply if desired
request_kw
=
None
,
# instance parameters, if instantiation
# testing is desired
software_timeout
=
3600
,
instance_timeout
=
3600
,
):
super
(
SoftwareReleaseTester
,
self
).
__init__
(
slap
,
slap_supply
,
slap_order
,
url
,
logger
)
self
.
name
=
name
self
.
computer_guid
=
computer_guid
if
isinstance
(
request_kw
,
str
)
or
\
isinstance
(
request_kw
,
unicode
):
self
.
request_kw
=
json
.
loads
(
request_kw
)
else
:
self
.
request_kw
=
request_kw
self
.
message_history
=
[]
self
.
state
=
TESTER_STATE_INITIAL
self
.
transition_dict
=
{
# step function
# delay
# next_state
# software_state
# instance_state
TESTER_STATE_INITIAL
:
(
lambda
t
:
None
,
None
,
TESTER_STATE_NOTHING
,
None
,
None
,
),
TESTER_STATE_NOTHING
:
(
lambda
t
:
t
.
_supply
(
"available"
),
int
(
software_timeout
),
request_kw
is
None
and
TESTER_STATE_INSTANCE_UNINSTALLED
or
\
TESTER_STATE_SOFTWARE_INSTALLED
,
SOFTWARE_STATE_INSTALLED
,
None
,
),
TESTER_STATE_SOFTWARE_INSTALLED
:
(
lambda
t
:
t
.
_request
(
"started"
),
int
(
instance_timeout
),
TESTER_STATE_INSTANCE_STARTED
,
None
,
INSTANCE_STATE_STARTED
,
),
TESTER_STATE_INSTANCE_STARTED
:
(
lambda
t
:
t
.
_request
(
"destroyed"
),
int
(
1200
),
TESTER_STATE_INSTANCE_UNINSTALLED
,
None
,
INSTANCE_STATE_STOPPED
,
),
TESTER_STATE_INSTANCE_UNINSTALLED
:
(
lambda
t
:
t
.
_supply
(
"destroyed"
),
int
(
1200
),
None
,
None
,
None
,
),
}
def
__repr__
(
self
):
deadline
=
self
.
deadline
if
deadline
is
not
None
:
deadline
-=
time
.
time
()
deadline
=
'+%is'
%
(
deadline
,
)
return
'<%s(state=%s, deadline=%s) at %x>'
%
(
self
.
__class__
.
__name__
,
self
.
state
,
deadline
,
id
(
self
))
# ROQUE: this method is a hack. This set must occur during request.
def
forceSetState
(
self
,
state
):
self
.
latest_state
=
state
def
getInfo
(
self
):
info
=
""
info
+=
"Software Release URL: %s
\
n
"
%
(
self
.
url
)
if
self
.
computer_guid
is
not
None
:
info
+=
"Supply requested on: %s
\
n
"
%
(
self
.
computer_guid
)
info
+=
"Instance Requested (Parameters): %s
\
n
"
%
self
.
request_kw
return
info
def
getFormatedLastMessage
(
self
):
if
len
(
self
.
message_history
)
==
0
:
return
"No message"
summary
=
"Summary about the test. Instance List and Status:
\
n
"
message
=
"Last information about the tester:
\
n
"
if
self
.
message_history
[
-
1
]
is
not
None
:
message_list
=
self
.
message_history
[
-
1
]
for
entry
in
message_list
:
summary
+=
"%s %s -> %s
\
n
"
%
(
entry
[
'title'
],
entry
[
"slave"
]
and
"(slave)"
or
""
,
entry
[
'state'
])
for
prop
in
entry
:
if
prop
!=
"information"
:
message
+=
"%s = %s
\
n
"
%
(
prop
,
json
.
dumps
(
entry
[
prop
],
indent
=
2
))
message
+=
"=== connection_dict ===
\
n
%s
\
n
"
%
(
json
.
dumps
(
entry
[
"information"
][
"connection_dict"
],
indent
=
2
))
message
+=
"
\
n
"
message
+=
"=== parameter_dict ===
\
n
%s
\
n
"
%
(
json
.
dumps
(
entry
[
"information"
][
"parameter_dict"
],
indent
=
2
))
message
+=
"
\
n
"
message
+=
"="
*
79
message
+=
"
\
n
\
n
\
n
"
return
summary
+
message
def
_getSoftwareState
(
self
):
if
self
.
computer_guid
is
None
:
return
SOFTWARE_STATE_INSTALLED
message
=
self
.
getSoftwareInstallationNews
()
if
message
.
startswith
(
"#error no data found"
):
return
SOFTWARE_STATE_UNKNOWN
if
message
.
startswith
(
'#access software release'
):
return
SOFTWARE_STATE_INSTALLED
if
message
.
startswith
(
'#error'
):
return
SOFTWARE_STATE_INSTALLING
return
SOFTWARE_STATE_UNKNOWN
@
retryOnNetworkFailure
def
getRSSEntryFromMonitoring
(
self
,
base_url
):
if
base_url
is
None
:
return
{}
feed_url
=
base_url
+
'/monitor-public/rssfeed.html'
d
=
feedparser
.
parse
(
feed_url
)
if
len
(
d
.
entries
)
>
0
:
return
{
"date"
:
d
.
entries
[
0
].
published
,
"message"
:
d
.
entries
[
0
].
description
,
"title"
:
d
.
entries
[
0
].
title
}
return
{}
@
retryOnNetworkFailure
def
_getInstanceState
(
self
):
latest_state
=
self
.
latest_state
self
.
_logger
(
'latest_state = %r'
,
latest_state
)
if
latest_state
is
None
:
return
INSTANCE_STATE_UNKNOWN
message_list
=
[]
try
:
self
.
log
(
"Curl to link: "
+
str
(
link
))
self
.
log
(
"GET to api "
+
str
(
api_path
))
self
.
connection
.
request
(
method
=
'GET'
,
url
=
api_path
,
body
=
""
)
self
.
log
(
"Request done. Getting response..."
)
response
=
self
.
connection
.
getresponse
()
self
.
log
(
"REPONSE.read: "
+
str
(
response
.
read
()))
return
json
.
loads
(
response
.
read
())
# Create and use new connection
except
:
self
.
log
(
"Request or response fail! Entering the while-try"
)
retry
=
0
# (re)Try several time to use new connection
while
retry
<
max_retry
:
for
instance
in
self
.
getInstanceUrlList
():
news
=
self
.
getNewsFromInstance
(
instance
[
"href"
])
information
=
self
.
getInformationFromInstance
(
instance
[
"href"
])
state
=
INSTANCE_STATE_UNKNOWN
monitor_information_dict
=
{}
info_created_at
=
"-1"
is_slave
=
information
[
'slave'
]
if
is_slave
:
self
.
_logger
.
debug
(
'Instance is slave'
)
if
(
information
[
"connection_dict"
])
>
0
:
state
=
INSTANCE_STATE_STARTED
else
:
# not slave
instance_state
=
news
[
0
]
if
instance_state
.
get
(
'created_at'
,
'-1'
)
!=
"-1"
:
# the following does NOT take TZ into account
created_at
=
datetime
.
datetime
.
strptime
(
instance_state
[
'created_at'
],
'%a, %d %b %Y %H:%M:%S %Z'
)
gmt_now
=
datetime
.
datetime
(
*
time
.
gmtime
()[:
6
])
info_created_at
=
'%s (%d)'
%
(
instance_state
[
'created_at'
],
(
gmt_now
-
created_at
).
seconds
)
if
instance_state
[
'text'
].
startswith
(
'#access'
):
state
=
INSTANCE_STATE_STARTED
if
instance_state
[
'text'
].
startswith
(
'#access Instance correctly stopped'
):
state
=
INSTANCE_STATE_STOPPED
if
instance_state
[
'text'
].
startswith
(
'#error'
):
state
=
INSTANCE_STATE_STARTED_WITH_ERROR
if
state
==
INSTANCE_STATE_STARTED_WITH_ERROR
:
# search for monitor url
monitor_v6_url
=
information
[
"connection_dict"
].
get
(
"monitor_v6_url"
)
try
:
self
.
log
(
"Retry number: "
+
str
(
retry
))
self
.
log
(
"entering _getConnection() to "
+
str
(
self
.
url
))
self
.
connection
=
self
.
_getConnection
(
self
.
certificate_path
,
self
.
key_path
,
self
.
url
)
self
.
log
(
"_getConnection DONE. Getting response..."
)
self
.
connection
.
request
(
method
=
'GET'
,
url
=
api_path
,
headers
=
{
'Accept'
:
link
[
'type'
]},
body
=
""
)
response
=
self
.
connection
.
getresponse
()
self
.
log
(
"REPONSE.read: "
+
str
(
response
.
read
()))
return
json
.
loads
(
response
.
read
())
except
Exception
,
e
:
self
.
log
(
"SlapOSMasterCommunicator: Connection failed.."
)
self
.
log
(
"EXCEPTION MESSAGE: "
+
str
(
e
))
retry
+=
1
time
.
sleep
(
10
)
self
.
log
(
"SlapOSMasterCommunicator: All connection attempts failed after %d try.."
%
max_retry
)
raise
ValueError
(
"SlapOSMasterCommunicator: Impossible to use connection"
)
def
_update_hosting_subscription_informations
(
self
):
"""
Add all not already visited hosting_subcription
# Visit all hosting subscriptions and fill a dict containing all
# new hosting subscriptions. ( like: {hs1_title:hs1_link, hs2_title:hs2_link, ..} )
# and a list of visited hosting_subsciption ( like: [hs1_link, hs2_link, ..] )
"""
collection
=
self
.
_curl
(
self
.
personnal_collection_link
)
# For each hosting_subcription present in the collection
for
hosting_subscription_link
in
collection
[
'_links'
][
'item'
]:
if
hosting_subscription_link
not
in
self
.
visited_hosting_subcriptions_link_list
:
hosting_subscription
=
self
.
_curl
(
hosting_subscription_link
)
self
.
hosting_subcriptions_dict
.
update
({
hosting_subscription
[
'title'
]:
hosting_subscription_link
})
self
.
visited_hosting_subcriptions_link_list
.
append
(
hosting_subscription_link
)
def
_getRelatedInstanceLink
(
self
,
hosting_subscription_title
):
"""
Return a list of all related instance_url from an hosting_subscription_title
"""
# Update informations
self
.
_update_hosting_subscription_informations
()
# Get specified hosting_subscription
hosting_subscription_link
=
self
.
hosting_subcriptions_dict
[
hosting_subscription_title
]
hosting_subscription
=
self
.
_curl
(
hosting_subscription_link
)
assert
(
hosting_subscription_title
==
hosting_subscription
[
'title'
])
# Get instance collection related to this hosting_subscription
instance_collection_link
=
hosting_subscription
[
'_links'
][
'http://slapos.org/reg/instance'
]
instance_collection
=
self
.
_curl
(
instance_collection_link
)
related_instance_link_list
=
[]
# For each instance present in the collection
for
instance
in
instance_collection
[
'_links'
][
'item'
]:
related_instance_link_list
.
append
(
instance
)
return
related_instance_link_list
def
getNewsFromInstanceLink
(
self
,
instance_link
):
instance
=
self
.
_curl
(
instance_link
)
news_link
=
instance
[
'_links'
][
'http://slapos.org/reg/news'
]
return
self
.
_curl
(
news_link
)
def
isHostingSubsciptionStatusEqualTo
(
self
,
hosting_subscription_title
,
excepted_news_text
):
"""
Return True if all related instance state are equal to status,
or False if not or if there is are no related instances.
"""
related_instance_link_list
=
_getRelatedInstanceLink
(
hosting_subscription_title
)
# For each instance present in the collection
for
instance_link
in
related_instance_link_list
:
news
=
self
.
getNewsFromInstanceLink
(
instance_link
)
if
excepted_news_text
!=
news
[
'news'
][
0
][
'text'
]:
return
False
return
len
(
related_instance_link_list
)
>
0
def
isInstanceReady
(
self
,
instance_link
,
status
):
"""
Return True if instance status and instance news text ~looks corresponding.
( use the matching of 'correctly' and 'Instance' and status )
"""
# XXX: SlapOS Master doesn't store any "news" about slave instances. Assume true.
if
self
.
_curl
(
instance_link
)[
'slave'
]:
return
True
text
=
self
.
getNewsFromInstanceLink
(
instance_link
)[
'news'
][
0
][
'text'
]
return
(
'Instance'
in
text
)
and
(
'correctly'
in
text
)
and
(
status
in
text
)
# check if provided 'status' = status
def
isHostingSubscriptionReady
(
self
,
hosting_subscription_title
,
status
):
"""
Return True if all instance status and instance news text ~looks corresponding.
( use the matching of 'correctly' and 'Instance' and status ).
"""
instance_link_list
=
self
.
_getRelatedInstanceLink
(
hosting_subscription_title
)
for
instance_link
in
instance_link_list
:
if
not
self
.
isInstanceReady
(
instance_link
,
status
):
return
False
return
len
(
instance_link_list
)
>
0
monitor_information_dict
=
self
.
getRSSEntryFromMonitoring
(
monitor_v6_url
)
self
.
_logger
(
"[DEBUG] monitor information dictionary: "
)
self
.
_logger
(
str
(
monitor_information_dict
))
except
Exception
:
self
.
_logger
.
exception
(
'Unable to download promises for: %s'
%
(
instance
[
"title"
]))
self
.
_logger
.
info
(
traceback
.
format_exc
())
monitor_information_dict
=
{
"message"
:
"Unable to download"
}
def
isRegisteredHostingSubscription
(
self
,
hosting_subscription_title
):
"""
Return True if the specified hosting_subscription is present on SlapOSMaster
"""
self
.
_update_hosting_subscription_informations
()
if
self
.
hosting_subcriptions_dict
.
get
(
hosting_subscription_title
):
return
True
return
False
self
.
_logger
(
'Instance state: %s -> %s'
%
(
instance
[
'title'
],
state
))
self
.
_logger
(
'Instance Created at: %s -> %s'
%
(
instance
[
'title'
],
info_created_at
))
def
getHostingSubscriptionDict
(
self
):
message_list
.
append
({
'title'
:
instance
[
"title"
],
'slave'
:
is_slave
,
'news'
:
news
[
0
],
'information'
:
information
,
'monitor'
:
monitor_information_dict
,
'state'
:
state
})
except
slapos
.
slap
.
ServerError
:
self
.
_logger
.
exception
(
'Got an error requesting partition for '
'its state'
)
return
INSTANCE_STATE_UNKNOWN
started
=
0
stopped
=
0
self
.
message_history
.
append
(
message_list
)
for
instance
in
message_list
:
if
not
instance
[
'slave'
]
and
\
instance
[
'state'
]
in
(
INSTANCE_STATE_UNKNOWN
,
INSTANCE_STATE_STARTED_WITH_ERROR
):
return
instance
[
'state'
]
elif
not
instance
[
'slave'
]
and
instance
[
'state'
]
==
INSTANCE_STATE_STARTED
:
started
=
1
elif
not
instance
[
'slave'
]
and
instance
[
'state'
]
==
INSTANCE_STATE_STOPPED
:
stopped
=
1
if
instance
[
'slave'
]
and
instance
[
'state'
]
==
INSTANCE_STATE_UNKNOWN
:
return
instance
[
'state'
]
if
started
and
stopped
:
return
INSTANCE_STATE_UNKNOWN
if
started
:
return
INSTANCE_STATE_STARTED
if
stopped
:
return
INSTANCE_STATE_STOPPED
@
retryOnNetworkFailure
def
teardown
(
self
):
"""
Return the dict of hosting subcription
.
Interrupt a running test sequence, putting it in idle state
.
"""
return
self
.
hosting_subcriptions_dict
self
.
_logger
.
info
(
'Invoking TearDown for %s@%s'
%
(
self
.
url
,
self
.
name
))
if
self
.
request_kw
is
not
None
:
self
.
_request
(
'destroyed'
)
if
self
.
computer_guid
is
not
None
:
self
.
_supply
(
'destroyed'
)
self
.
state
=
TESTER_STATE_INSTANCE_UNINSTALLED
def
getHostingSubscriptionInformationDict
(
self
,
title
):
def
tic
(
self
,
now
):
"""
Return a dict with informations about Hosting subscription
Check for missed deadlines (-> test failure), conditions for moving to
next state, and actually moving to next state (executing its payload).
"""
related_instance_link_list
=
self
.
_getRelatedInstanceLink
(
title
)
related_instance_link
=
None
# Get root instance
for
link
in
related_instance_link_list
:
instance
=
self
.
_curl
(
link
)
if
title
==
instance
[
'title'
]:
related_instance_link
=
link
break
# Return information dict
if
related_instance_link
:
related_instance
=
self
.
_curl
(
related_instance_link
)
return
{
'title'
:
related_instance
[
'title'
],
'status'
:
related_instance
[
'status'
],
'software_url'
:
related_instance
[
'_links'
][
'http://slapos.org/reg/release'
],
'software_type'
:
related_instance
[
'software_type'
],
'computer_guid'
:
related_instance
[
'sla'
][
'computer_guid'
]
}
else
:
self
.
_logger
.
debug
(
'TIC'
)
deadline
=
self
.
deadline
if
deadline
<
now
and
deadline
is
not
None
:
raise
TestTimeout
(
self
.
state
)
_
,
_
,
next_state
,
software_state
,
instance_state
=
self
.
transition_dict
[
self
.
state
]
if
(
software_state
is
None
or
software_state
==
self
.
_getSoftwareState
())
and
(
instance_state
is
None
or
instance_state
==
self
.
_getInstanceState
()):
self
.
_logger
.
debug
(
'Going to state %s (%r)'
,
next_state
,
instance_state
)
if
next_state
is
None
:
return
None
self
.
state
=
next_state
stepfunc
,
delay
,
_
,
_
,
_
=
self
.
transition_dict
[
next_state
]
self
.
deadline
=
now
+
delay
stepfunc
(
self
)
return
self
.
deadline
erp5/util/testnode/testnode.py
View file @
c8d33446
...
...
@@ -65,6 +65,7 @@ class TestNode(object):
max_temp_time
=
MAX_TEMP_TIME
):
self
.
testnode_log
=
log
self
.
log
=
log
self
.
log
(
"Config parameter in TestNode.init(): "
+
str
(
config
))
self
.
config
=
config
or
{}
self
.
process_manager
=
ProcessManager
(
log
)
self
.
working_directory
=
config
[
'working_directory'
]
...
...
@@ -405,9 +406,14 @@ shared = true
node_test_suite
.
edit
(
test_result
=
test_result
)
# get cluster configuration for this test suite, this is needed to
# know slapos parameters to user for creating instances
node_test_suite
.
edit
(
cluster_configuration
=
Utils
.
deunicodeData
(
json
.
loads
(
self
.
test_suite_portal
.
generateConfiguration
(
node_test_suite
.
test_suite_title
))[
'configuration_list'
][
0
]))
log
(
"Getting configuration from test suite "
+
str
(
node_test_suite
.
test_suite_title
))
generated_config
=
self
.
test_suite_portal
.
generateConfiguration
(
node_test_suite
.
test_suite_title
)
log
(
"Generated configuration: "
+
str
(
generated_config
))
jsonData
=
json
.
loads
(
generated_config
)
cluster_configuration
=
Utils
.
deunicodeData
(
jsonData
[
'configuration_list'
][
0
])
node_test_suite
.
edit
(
cluster_configuration
=
cluster_configuration
)
# Now prepare the installation of SlapOS and create instance
status_dict
=
runner
.
prepareSlapOSForTestSuite
(
node_test_suite
)
# Give some time so computer partitions may start
...
...
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