Commit 23a5a1f0 authored by Roque's avatar Roque Committed by Klaus Wölfel

tesnode: slapos master communicator handles frontend request

- communicator considers requests of master frontend and instance destruction.
- communicator retrieves frontend related information from instances.
- minor refactoring and code cleanup.
parent 275d71e4
...@@ -2,7 +2,7 @@ import datetime ...@@ -2,7 +2,7 @@ import datetime
import json import json
import traceback import traceback
import time import time
#import feedparser import requests
from functools import wraps from functools import wraps
from uritemplate import expand from uritemplate import expand
...@@ -12,8 +12,8 @@ from requests.exceptions import HTTPError ...@@ -12,8 +12,8 @@ from requests.exceptions import HTTPError
from ..taskdistribution import SAFE_RPC_EXCEPTION_LIST from ..taskdistribution import SAFE_RPC_EXCEPTION_LIST
from . import logger from . import logger
# max time to instance changing state: 2 hour # max time to instance changing state: 3 hour
MAX_INSTANCE_TIME = 60*60*2 MAX_INSTANCE_TIME = 60*60*3
SOFTWARE_PRODUCT_NAMESPACE = "product." SOFTWARE_PRODUCT_NAMESPACE = "product."
...@@ -89,19 +89,24 @@ class SlapOSMasterCommunicator(object): ...@@ -89,19 +89,24 @@ class SlapOSMasterCommunicator(object):
return self.slap_supply.supply(self.url, self.computer_guid) return self.slap_supply.supply(self.url, self.computer_guid)
@retryOnNetworkFailure @retryOnNetworkFailure
def _request(self, state, instance_title=None, request_kw=None): def _request(self, state, instance_title=None, request_kw=None, shared=False, software_type="RootSoftwareInstance"):
if instance_title is not None: if instance_title is not None:
self.name = instance_title self.name = instance_title
if request_kw is not None: if request_kw is not None:
if isinstance(request_kw, basestring): if isinstance(request_kw, basestring) or \
isinstance(request_kw, unicode):
self.request_kw = json.loads(request_kw) self.request_kw = json.loads(request_kw)
else: else:
self.request_kw = request_kw self.request_kw = request_kw
if self.request_kw is None:
self.request_kw = {}
logger.info('Request %s@%s: %s', self.url, self.name, state) logger.info('Request %s@%s: %s', self.url, self.name, state)
self.latest_state = state self.latest_state = state
return self.slap_order.request( return self.slap_order.request(
software_release=self.url, software_release=self.url,
software_type="RootSoftwareInstance",
partition_reference=self.name, partition_reference=self.name,
shared=shared,
state=state, state=state,
**self.request_kw) **self.request_kw)
...@@ -134,9 +139,9 @@ class SlapOSMasterCommunicator(object): ...@@ -134,9 +139,9 @@ class SlapOSMasterCommunicator(object):
@retryOnNetworkFailure @retryOnNetworkFailure
def getSoftwareInstallationList(self): def getSoftwareInstallationList(self, computer_guid=None):
# XXX Move me to slap.py API # XXX Move me to slap.py API
computer = self._hateoas_getComputer(self.computer_guid) computer = self._hateoas_getComputer(computer_guid) if computer_guid else self._hateoas_getComputer(self.computer_guid)
# Not a list ? # Not a list ?
action = computer['_links']['action_object_slap'] action = computer['_links']['action_object_slap']
...@@ -151,9 +156,9 @@ class SlapOSMasterCommunicator(object): ...@@ -151,9 +156,9 @@ class SlapOSMasterCommunicator(object):
@retryOnNetworkFailure @retryOnNetworkFailure
def getSoftwareInstallationNews(self): def getSoftwareInstallationNews(self, computer_guid=None):
getter_link = None getter_link = None
for si in self.getSoftwareInstallationList(): for si in self.getSoftwareInstallationList(computer_guid):
if si["title"] == self.url: if si["title"] == self.url:
getter_link = si["href"] getter_link = si["href"]
break break
...@@ -219,11 +224,12 @@ class SlapOSMasterCommunicator(object): ...@@ -219,11 +224,12 @@ class SlapOSMasterCommunicator(object):
result = self.hateoas_navigator.GET(object_link) result = self.hateoas_navigator.GET(object_link)
return json.loads(result) return json.loads(result)
def _getSoftwareState(self): def _getSoftwareState(self, computer_guid=None):
if self.computer_guid is None: if self.computer_guid is None:
return SOFTWARE_STATE_INSTALLED return SOFTWARE_STATE_INSTALLED
message = self.getSoftwareInstallationNews() message = self.getSoftwareInstallationNews(computer_guid)
logger.info(message)
if message.startswith("#error no data found"): if message.startswith("#error no data found"):
return SOFTWARE_STATE_UNKNOWN return SOFTWARE_STATE_UNKNOWN
...@@ -288,6 +294,9 @@ class SlapOSMasterCommunicator(object): ...@@ -288,6 +294,9 @@ class SlapOSMasterCommunicator(object):
if instance_state['text'].startswith('#access Instance correctly stopped'): if instance_state['text'].startswith('#access Instance correctly stopped'):
state = INSTANCE_STATE_STOPPED state = INSTANCE_STATE_STOPPED
if instance_state['text'].startswith('#destroy'):
state = INSTANCE_STATE_DESTROYED
if instance_state['text'].startswith('#error'): if instance_state['text'].startswith('#error'):
state = INSTANCE_STATE_STARTED_WITH_ERROR state = INSTANCE_STATE_STARTED_WITH_ERROR
...@@ -297,8 +306,8 @@ class SlapOSMasterCommunicator(object): ...@@ -297,8 +306,8 @@ class SlapOSMasterCommunicator(object):
try: try:
monitor_information_dict = self.getRSSEntryFromMonitoring(monitor_v6_url) monitor_information_dict = self.getRSSEntryFromMonitoring(monitor_v6_url)
except Exception: except Exception:
logger.exception('Unable to download promises for: %s', logger.exception('Unable to download promises for: %s', instance["title"])
instance["title"]) logger.error(traceback.format_exc())
monitor_information_dict = {"message": "Unable to download"} monitor_information_dict = {"message": "Unable to download"}
message_list.append({ message_list.append({
...@@ -357,8 +366,7 @@ class SlapOSMasterCommunicator(object): ...@@ -357,8 +366,7 @@ class SlapOSMasterCommunicator(object):
if (time.time()-start_time) > max_time: if (time.time()-start_time) > max_time:
error_message = "Instance '%s' not '%s' after %s seconds" %(instance_title, state, str(time.time()-start_time)) error_message = "Instance '%s' not '%s' after %s seconds" %(instance_title, state, str(time.time()-start_time))
return {'error_message' : error_message} return {'error_message' : error_message}
logger.info("Instance correctly '%s' after %s seconds.", logger.info("Instance correctly '%s' after %s seconds.", state, time.time() - start_time)
state, time.time() - start_time)
return {'error_message' : None} return {'error_message' : None}
class SlapOSTester(SlapOSMasterCommunicator): class SlapOSTester(SlapOSMasterCommunicator):
...@@ -400,22 +408,20 @@ class SlapOSTester(SlapOSMasterCommunicator): ...@@ -400,22 +408,20 @@ class SlapOSTester(SlapOSMasterCommunicator):
self.computer_guid = computer_guid self.computer_guid = computer_guid
self._supply() self._supply()
def requestInstanceStart(self, instance_title=None, request_kw=None): def requestInstanceStart(self, instance_title=None, request_kw=None, shared=False, software_type="RootSoftwareInstance"):
self._request(INSTANCE_STATE_STARTED, instance_title, request_kw) self.instance = self._request(INSTANCE_STATE_STARTED, instance_title, request_kw, shared, software_type)
def requestInstanceStop(self, instance_title=None, request_kw=None): def requestInstanceStop(self, instance_title=None, request_kw=None, shared=False):
self._request(INSTANCE_STATE_STOPPED, instance_title, request_kw) self._request(INSTANCE_STATE_STOPPED, instance_title, request_kw, shared)
def requestInstanceDestroy(self, instance_title=None, request_kw=None): def requestInstanceDestroy(self, instance_title=None, request_kw=None, shared=False):
self._request(INSTANCE_STATE_DESTROYED, instance_title, request_kw) self._request(INSTANCE_STATE_DESTROYED, instance_title, request_kw, shared)
def waitInstanceStarted(self, instance_title): def waitInstanceStarted(self, instance_title):
error_message = self._waitInstance(instance_title, INSTANCE_STATE_STARTED)["error_message"] error_message = self._waitInstance(instance_title, INSTANCE_STATE_STARTED)["error_message"]
if error_message is not None: if error_message is not None:
logger.error(error_message) logger.error(error_message)
logger.error("Do you use instance state propagation in your project?") logger.error("Instance '%s' will be stopped and test aborted.", instance_title)
logger.error("Instance '%s' will be stopped and test aborted.",
instance_title)
self.requestInstanceStop() self.requestInstanceStop()
time.sleep(60) time.sleep(60)
raise ValueError(error_message) raise ValueError(error_message)
...@@ -424,16 +430,60 @@ class SlapOSTester(SlapOSMasterCommunicator): ...@@ -424,16 +430,60 @@ class SlapOSTester(SlapOSMasterCommunicator):
error_message = self._waitInstance(instance_title, INSTANCE_STATE_STOPPED)["error_message"] error_message = self._waitInstance(instance_title, INSTANCE_STATE_STOPPED)["error_message"]
if error_message is not None: if error_message is not None:
logger.error(error_message) logger.error(error_message)
logger.error("Do you use instance state propagation in your project?")
raise ValueError(error_message) raise ValueError(error_message)
def waitInstanceDestroyed(self, instance_title): def waitInstanceDestroyed(self, instance_title):
error_message = self._waitInstance(instance_title, INSTANCE_STATE_DESTROYED)["error_message"] error_message = self._waitInstance(instance_title, INSTANCE_STATE_DESTROYED)["error_message"]
if error_message is not None: if error_message is not None:
logger.error(error_message) logger.error(error_message)
logger.error("Do you use instance state propagation in your project?")
raise ValueError(error_message) raise ValueError(error_message)
def getMasterFrontendDict(self):
frontend_master_ipv6 = None
instance_guid = None
for instance in self.getInstanceUrlList():
if instance["title"] == "Monitor Frontend apache-frontend-1":
try:
information = self.getInformationFromInstance(instance["href"])
frontend_master_ipv6 = information['parameter_dict']['url']
except Exception as e:
pass
return {'instance_guid' : self.instance.getInstanceGuid(), 'frontend_master_ipv6' : frontend_master_ipv6}
def getInstanceUrlDict(self):
frontend_url_list = []
zope_address_list = []
for instance in self.getInstanceUrlList():
information = self.getInformationFromInstance(instance["href"])
if "frontend-" in instance["title"]:
try:
# TODO: this should get "secure_access" value (https). Until having a
# valid certificate, the "site_url" (http) will be used.
frontend = [instance["title"].replace("frontend-", ""),
information["connection_dict"]["site_url"]]
frontend_url_list.append(frontend)
except Exception as e:
logger.info("Frontend url not generated yet for instance: " + instance["title"])
pass
if instance["title"] == self.name:
try:
connection_json = json.loads(information["connection_dict"]["_"])
user = connection_json["inituser-login"]
password = connection_json["inituser-password"]
except Exception as e:
raise ValueError("user and password not found in connection parameters. Error while instantiating?")
if "zope-" in instance["title"]:
try:
connection_dict = information["connection_dict"]["_"]
address = json.loads(connection_dict)["zope-address-list"][0][0]
zope = [instance["title"].replace("zope-", ""), address]
zope_address_list.append(zope)
except Exception as e:
logger.info("zope address not found in connection parameters. Error while instantiating?")
pass
return {'zope-address-list' : zope_address_list, 'user' : user,
'password' : password, 'frontend-url-list' : frontend_url_list }
class SoftwareReleaseTester(SlapOSTester): class SoftwareReleaseTester(SlapOSTester):
deadline = None deadline = None
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment