Example #1
0
    def request_work(self,
                     onlynewwho: bool = False,
                     throttle: bool = False) -> None:
        """Request work from order manager."""
        # Allow requesting work only once every 10 seconds when throttling
        if self._requested_work_time and throttle is True:
            time_elapsed = time.time() - self._requested_work_time
            if time_elapsed < 10:
                return

        self._requested_work_time = time.time()

        if onlynewwho:
            request = RequestFromRobot(self.lgnum,
                                       self.rsrc,
                                       requestnewwho=True)
        else:
            request = RequestFromRobot(self.lgnum, self.rsrc, requestwork=True)

        _LOGGER.info('Requesting work from order manager')

        dtype = create_robcoewmtype_str(request)
        success = self.send_robot_request(dtype, unstructure(request))

        if success is True:
            _LOGGER.info('Requested work from order manager')
        else:
            _LOGGER.error(
                'Error requesting work from order manager. Try again')
            raise ConnectionError
Example #2
0
    def notify_who_completion(self, who: str) -> None:
        """
        Send a  warehouse order completion request to EWM Order Manager.

        It notifies the robot when the warehouse order was completed.
        """
        request = RequestFromRobot(self.lgnum,
                                   self.rsrc,
                                   notifywhocompletion=who)

        _LOGGER.info(
            'Requesting warehouse order completion notification for %s from order manager',
            who)

        dtype = create_robcoewmtype_str(request)
        success = self.send_robot_request(dtype, unstructure(request))

        if success is True:
            _LOGGER.info(
                'Requested warehouse order completion notification from order manager'
            )
        else:
            _LOGGER.error(
                'Error requesting warehouse order completion notification from order manager. '
                'Try again')
            raise ConnectionError
Example #3
0
    def confirm_warehousetask(self,
                              wht: WarehouseTask,
                              enforce_first_conf: bool = False) -> None:
        """Confirm warehouse task."""
        confirmations = []
        clear_progress = False
        if wht.vlpla or enforce_first_conf:
            confirmation = ConfirmWarehouseTask(
                lgnum=wht.lgnum,
                tanum=wht.tanum,
                rsrc=self.rsrc,
                who=wht.who,
                confirmationnumber=ConfirmWarehouseTask.FIRST_CONF,
                confirmationtype=ConfirmWarehouseTask.CONF_SUCCESS)
            if enforce_first_conf:
                _LOGGER.info('First confirmation enforced - confirming')
            else:
                _LOGGER.info('Source bin reached - confirming')
            confirmations.append(confirmation)
        elif wht.nlpla:
            confirmation = ConfirmWarehouseTask(
                lgnum=wht.lgnum,
                tanum=wht.tanum,
                rsrc=self.rsrc,
                who=wht.who,
                confirmationnumber=ConfirmWarehouseTask.SECOND_CONF,
                confirmationtype=ConfirmWarehouseTask.CONF_SUCCESS)
            _LOGGER.info('Target bin reached - confirming')
            confirmations.append(confirmation)
            clear_progress = True

        for confirmation in confirmations:
            dtype = create_robcoewmtype_str(confirmation)
            success = self.send_wht_confirmation(dtype,
                                                 unstructure(confirmation),
                                                 clear_progress)

            if success is True:
                _LOGGER.info(
                    'Confirmation message for warehouse task "%s" sent to order manager',
                    wht.tanum)
            else:
                _LOGGER.error(
                    'Error sending confirmation message for warehouse task "%s" - Try again',
                    wht.tanum)
                raise ConnectionError
Example #4
0
    def send_robot_whos(self, robotident: RobotIdentifier,
                        whos: List[WarehouseOrder]) -> None:
        """
        Send warehouse order from SAP EWM to the robot.

        Returns True on success and False on fail.
        """
        # Send orders to robot
        for who in whos:
            dtype = create_robcoewmtype_str(who)
            self.ordercontroller.send_who_to_robot(robotident, dtype,
                                                   unstructure(who))

        # Create success log message
        whos_who = [entry.who for entry in whos]
        _LOGGER.info(
            'Warehouse orders "%s" sent to robot "%s" in warehouse "%s"',
            whos_who, robotident.rsrc, robotident.lgnum)
Example #5
0
    def send_warehousetask_error(self, wht: WarehouseTask) -> None:
        """Send warehouse task error."""
        errors = []
        if wht.vlpla:
            error = ConfirmWarehouseTask(
                lgnum=wht.lgnum,
                tanum=wht.tanum,
                rsrc=self.rsrc,
                who=wht.who,
                confirmationnumber=ConfirmWarehouseTask.FIRST_CONF,
                confirmationtype=ConfirmWarehouseTask.CONF_ERROR)
            _LOGGER.info('Error before first confirmation - sending to EWM')
            errors.append(error)
        elif wht.nlpla:
            error = ConfirmWarehouseTask(
                lgnum=wht.lgnum,
                tanum=wht.tanum,
                rsrc=self.rsrc,
                who=wht.who,
                confirmationnumber=ConfirmWarehouseTask.SECOND_CONF,
                confirmationtype=ConfirmWarehouseTask.CONF_ERROR)
            _LOGGER.info('Error before second confirmation - sending to EWM')
            errors.append(error)

        for error in errors:
            dtype = create_robcoewmtype_str(error)
            success = self.send_wht_confirmation(dtype, unstructure(error),
                                                 True)

            if success is True:
                _LOGGER.info(
                    'Confirmation message for warehouse task "%s" sent to order manager',
                    wht.tanum)
            else:
                _LOGGER.error(
                    'Error sending confirmation message for warehouse task "%s" - Try again',
                    wht.tanum)
                raise ConnectionError
import sys
import traceback
import logging

from typing import Dict

from robcoewmtypes.helper import create_robcoewmtype_str, get_sample_cr
from robcoewmtypes.robot import RequestFromRobot, RequestFromRobotStatus

from robcoewminterface.exceptions import NoOrderFoundError, RobotHasOrderError

from k8scrhandler.k8scrhandler import K8sCRHandler, k8s_cr_callback

_LOGGER = logging.getLogger(__name__)

ROBOTREQUEST_TYPE = create_robcoewmtype_str(RequestFromRobot('lgnum', 'rsrc'))


class RobotRequestController(K8sCRHandler):
    """Handle K8s custom resources."""
    def __init__(self) -> None:
        """Constructor."""
        template_cr = get_sample_cr('robotrequest')

        labels = {}
        super().__init__('sap.com', 'v1', 'robotrequests', 'default',
                         template_cr, labels)

    @k8s_cr_callback
    def _callback(self, name: str, labels: Dict, operation: str,
                  custom_res: Dict) -> None:
Example #7
0
    def robotrequest_callback(self, dtype: str, name: str, data: Dict,
                              statusdata: Dict) -> None:
        """
        Handle robotrequest messages.

        Used for K8S CR handler.
        """
        cls = self.__class__

        # Structure the request data
        robcoewmdata = self._structure_callback_data(
            dtype, data, cls.ROBOTREQUEST_MSG_TYPES)
        if not robcoewmdata:
            return
        # Get statusdata if available
        if statusdata:
            robcoewmstatusdata = self._structure_callback_data(
                dtype, statusdata, cls.ROBOTREQUEST_MSG_TYPES)
        else:
            robcoewmstatusdata = [
                RequestFromRobot(robcoewmdata[0].lgnum, robcoewmdata[0].rsrc),
            ]

        if len(robcoewmdata) > 1 or len(robcoewmstatusdata) > 1:
            raise ValueError('Robot request must include only one dataset')

        # Process the dataset
        request = robcoewmdata[0]
        status = robcoewmstatusdata[0]

        # Return if request was already processed
        if self.msg_mem.check_robotrequest_processed(name, status):
            _LOGGER.info('Robot request "%s" already processed before - skip',
                         name)
            return

        robotident = RobotIdentifier(request.lgnum, request.rsrc)
        # Determine if it is the first request
        request_no = self.msg_mem.request_count[robotident]
        firstrequest = bool(request_no == 0)
        # Request work, when robot is asking
        if request.requestnewwho and not status.requestnewwho:
            # Get a new warehouse order for the robot
            success = self.get_and_send_robot_whos(robotident,
                                                   firstrequest=firstrequest,
                                                   newwho=True,
                                                   onlynewwho=True)
            if success:
                status.requestnewwho = True
                status.requestwork = request.requestwork
        elif request.requestwork and not status.requestwork:
            # Get existing warehouse orders for the robot. If no exists, get a new warehouse order
            success = self.get_and_send_robot_whos(robotident,
                                                   firstrequest=firstrequest,
                                                   newwho=True,
                                                   onlynewwho=False)
            if success:
                status.requestwork = True

        # Check if warehouse order was completed
        if request.notifywhocompletion and not status.notifywhocompletion:
            try:
                self.ewmwho.get_robot_warehouseorders(robotident.lgnum,
                                                      robotident.rsrc)
            except NoOrderFoundError:
                status.notifywhocompletion = request.notifywhocompletion
                _LOGGER.info(
                    'Warehouse order %s was confirmed, notifying robot "%s"',
                    request.notifywhocompletion, robotident.rsrc)

        # Raise exception if request was not complete
        if request == status:
            self.update_robotrequest_status(name,
                                            create_robcoewmtype_str(status),
                                            unstructure(status),
                                            process_complete=True)
            self.msg_mem.memorize_robotrequest(name, status)
            self.msg_mem.delete_robotrequest_from_memory(name, status)
        else:
            self.update_robotrequest_status(name,
                                            create_robcoewmtype_str(status),
                                            unstructure(status),
                                            process_complete=False)
            self.msg_mem.memorize_robotrequest(name, status)
            if request.notifywhocompletion:
                raise RobotHasOrderError
            else:
                raise NoOrderFoundError
from collections import OrderedDict
from typing import Dict
from cattr import structure

from robcoewmtypes.helper import create_robcoewmtype_str, get_sample_cr
from robcoewmtypes.warehouseorder import (
    WarehouseOrder, ConfirmWarehouseTask, WarehouseOrderCRDSpec)

from k8scrhandler.k8scrhandler import K8sCRHandler, k8s_cr_callback

from .manager import RobotIdentifier

_LOGGER = logging.getLogger(__name__)

WAREHOUSEORDER_TYPE = create_robcoewmtype_str(WarehouseOrder('lgnum', 'who'))
WAREHOUSETASKCONF_TYPE = create_robcoewmtype_str(ConfirmWarehouseTask(
    'lgnum', 'who', ConfirmWarehouseTask.FIRST_CONF, ConfirmWarehouseTask.CONF_SUCCESS))


class OrderController(K8sCRHandler):
    """Handle K8s custom resources."""

    def __init__(self) -> None:
        """Constructor."""
        # Warehouse order spec dictionary
        self.warehouse_order_spec = OrderedDict()
        self.warehouse_order_spec_lock = threading.RLock()

        template_cr = get_sample_cr('warehouseorder')
Example #9
0
import traceback
import logging

from typing import Dict, Optional

from robcoewmtypes.helper import create_robcoewmtype_str, get_sample_cr
from robcoewmtypes.warehouseorder import (
    WarehouseOrder, ConfirmWarehouseTask, WarehouseOrderCRDSpec)

from k8scrhandler.k8scrhandler import K8sCRHandler, k8s_cr_callback

from .robot import WarehouseOrderStateRestore

_LOGGER = logging.getLogger(__name__)

WAREHOUSEORDER_TYPE = create_robcoewmtype_str(WarehouseOrder('lgnum', 'who'))


class OrderController(K8sCRHandler):
    """Handle K8s custom resources."""

    def __init__(self) -> None:
        """Constructor."""
        self.init_robot_fromenv()
        # Last successfully processed spec of warehouse order
        self.processed_order_spec = {}

        template_cr = get_sample_cr('warehouseorder')

        labels = {}
        labels['cloudrobotics.com/robot-name'] = self.robco_robot_name
Example #10
0
    def process_robotrequest_cr(self, name: str, custom_res: Dict) -> None:
        """
        Process a robotrequest custom resource.

        Used for K8S CR handler.
        """
        cls = self.__class__

        if custom_res.get(
                'status',
            {}).get('status') == RequestFromRobotStatus.STATE_PROCESSED:
            return

        # Structure the request data
        robcoewmdata = self._structure_callback_data(
            ROBOTREQUEST_TYPE, custom_res['spec'], cls.ROBOTREQUEST_MSG_TYPES)
        if not robcoewmdata:
            return
        # Get statusdata if available
        if custom_res.get('status', {}).get('data'):
            robcoewmstatusdata = self._structure_callback_data(
                ROBOTREQUEST_TYPE, custom_res['status']['data'],
                cls.ROBOTREQUEST_MSG_TYPES)
        else:
            robcoewmstatusdata = [
                RequestFromRobot(robcoewmdata[0].lgnum, robcoewmdata[0].rsrc),
            ]

        if len(robcoewmdata) > 1 or len(robcoewmstatusdata) > 1:
            raise ValueError('Robot request must include only one dataset')

        # Process the dataset
        request = robcoewmdata[0]
        status = robcoewmstatusdata[0]

        # Return if request was already processed
        if self.msg_mem.check_robotrequest_processed(name, status):
            _LOGGER.info('Robot request "%s" already processed before - skip',
                         name)
            return

        robotident = RobotIdentifier(request.lgnum, request.rsrc)
        # Determine if it is the first request
        self.msg_mem.request_count[name] += 1
        firstrequest = bool(self.msg_mem.request_count[name] == 1)
        # Request work, when robot is asking
        if request.requestnewwho and not status.requestnewwho:
            # Get a new warehouse order for the robot
            success = self.get_and_send_robot_whos(robotident,
                                                   firstrequest=firstrequest,
                                                   newwho=True,
                                                   onlynewwho=True)
            if success:
                status.requestnewwho = True
                status.requestwork = request.requestwork
        elif request.requestwork and not status.requestwork:
            # Get existing warehouse orders for the robot. If no exists, get a new warehouse order
            success = self.get_and_send_robot_whos(robotident,
                                                   firstrequest=firstrequest,
                                                   newwho=True,
                                                   onlynewwho=False)
            if success:
                status.requestwork = True

        # Check if warehouse order was completed
        if request.notifywhocompletion and not status.notifywhocompletion:
            notfound = False
            try:
                who = self.ewmwho.get_warehouseorder(
                    lgnum=robotident.lgnum, who=request.notifywhocompletion)
            except NotFoundError:
                notfound = True
            else:
                if who.status not in ['D', '']:
                    notfound = True
            if notfound:
                status.notifywhocompletion = request.notifywhocompletion
                _LOGGER.info(
                    'Warehouse order %s was confirmed, notifying robot "%s"',
                    request.notifywhocompletion, robotident.rsrc)
                # Warehouse orders are completed in EWM, thus ensure that they are marked PROCESSED
                self.cleanup_who(
                    WhoIdentifier(robotident.lgnum,
                                  request.notifywhocompletion))

        # Check if warehouse task was completed
        if request.notifywhtcompletion and not status.notifywhtcompletion:
            try:
                self.ewmwho.get_openwarehousetask(robotident.lgnum,
                                                  request.notifywhtcompletion)
            except NotFoundError:
                status.notifywhtcompletion = request.notifywhtcompletion
                _LOGGER.info(
                    'Warehouse task %s was confirmed, notifying robot "%s"',
                    request.notifywhtcompletion, robotident.rsrc)

        # Raise exception if request was not complete
        if request == status:
            self.robotrequestcontroller.update_status(
                name,
                create_robcoewmtype_str(status),
                unstructure(status),
                process_complete=True)
            self.msg_mem.memorize_robotrequest(name, status)
            self.msg_mem.delete_robotrequest_from_memory(name, status)
        else:
            self.robotrequestcontroller.update_status(
                name,
                create_robcoewmtype_str(status),
                unstructure(status),
                process_complete=False)
            self.msg_mem.memorize_robotrequest(name, status)
            if request.notifywhocompletion:
                raise RobotHasOrderError
            else:
                raise NoOrderFoundError
Example #11
0
from robcoewminterface.ewm import WarehouseOData, WarehouseOrderOData
from robcoewminterface.exceptions import (ODataAPIException, NoOrderFoundError,
                                          RobotHasOrderError,
                                          WarehouseTaskAlreadyConfirmedError,
                                          NotFoundError)

from .helper import ProcessedMessageMemory, RobotIdentifier, WhoIdentifier
from .ordercontroller import OrderController
from .robotrequestcontroller import RobotRequestController

_LOGGER = logging.getLogger(__name__)

STATE_SUCCEEDED = 'SUCCEEDED'
STATE_FAILED = 'FAILED'

ROBOTREQUEST_TYPE = create_robcoewmtype_str(RequestFromRobot('lgnum', 'rsrc'))
WAREHOUSETASKCONF_TYPE = create_robcoewmtype_str([
    ConfirmWarehouseTask('lgnum', 'who', ConfirmWarehouseTask.FIRST_CONF,
                         ConfirmWarehouseTask.CONF_SUCCESS)
])


class EWMOrderManager:
    """Main order manager class for EWM."""

    ROBOTREQUEST_MSG_TYPES = (RequestFromRobot, )
    CONFIRMATION_MSG_TYPES = (ConfirmWarehouseTask, )

    # Prometheus logging
    who_counter = Counter('sap_ewm_warehouse_orders',
                          'Completed EWM Warehouse orders',