2 # -------------------------------------------------------------------------
3 # Copyright (c) 2015-2017 AT&T Intellectual Property
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # -------------------------------------------------------------------------
24 from oslo_config import cfg
25 from oslo_log import log
27 from conductor.common.music import api
28 from conductor.common.music import messaging as music_messaging
29 from conductor.controller import translator
30 from conductor.i18n import _LE, _LI
31 from conductor import messaging
33 LOG = log.getLogger(__name__)
38 cfg.IntOpt('polling_interval',
41 help='Time between checking for new plans. '
42 'Default value is 1.'),
45 CONF.register_opts(CONTROLLER_OPTS, group='controller')
48 class TranslatorService(cotyledon.Service):
49 """Template Translator service.
51 This service looks for untranslated templates and
52 preps them for solving by the Solver service.
55 # This will appear in 'ps xaf'
56 name = "Template Translator"
58 def __init__(self, worker_id, conf, **kwargs):
60 LOG.debug("%s" % self.__class__.__name__)
61 super(TranslatorService, self).__init__(worker_id)
62 self._init(conf, **kwargs)
65 def _init(self, conf, **kwargs):
67 self.Plan = kwargs.get('plan_class')
70 # Set up the RPC service(s) we want to talk to.
71 self.data_service = self.setup_rpc(conf, "data")
73 # Set up Music access.
74 self.music = api.API()
76 def _gracefully_stop(self):
77 """Gracefully stop working on things"""
81 """Prepare to restart the service"""
84 def setup_rpc(self, conf, topic):
85 """Set up the RPC Client"""
86 # TODO(jdandrea): Put this pattern inside music_messaging?
87 transport = messaging.get_transport(conf=conf)
88 target = music_messaging.Target(topic=topic)
89 client = music_messaging.RPCClient(conf=conf,
94 def translate(self, plan):
95 """Translate the plan to a format the solver can use"""
96 # Update the translation field and set status to TRANSLATED.
98 LOG.info(_LI("Requesting plan {} translation").format(
100 trns = translator.Translator(
101 self.conf, plan.name, plan.id, plan.template)
104 plan.translation = trns.translation
105 plan.status = self.Plan.TRANSLATED
107 "Plan {} translated. Ready for solving").format(
110 plan.message = trns.error_message
111 plan.status = self.Plan.ERROR
113 "Plan {} translation error encountered").format(
115 except Exception as ex:
116 template = "An exception of type {0} occurred, arguments:\n{1!r}"
117 plan.message = template.format(type(ex).__name__, ex.args)
118 plan.status = self.Plan.ERROR
122 def __check_for_templates(self):
123 """Wait for the polling interval, then do the real template check."""
125 # Wait for at least poll_interval sec
126 polling_interval = self.conf.controller.polling_interval
127 time.sleep(polling_interval)
129 # Look for plans with the status set to TEMPLATE
130 plans = self.Plan.query.all()
132 # If there's a template to be translated, do it!
133 if plan.status == self.Plan.TEMPLATE:
137 # Move plan to error status? Create a new timed-out status?
143 LOG.debug("%s" % self.__class__.__name__)
145 # Look for templates to translate from within a thread
146 executor = futurist.ThreadPoolExecutor()
148 fut = executor.submit(self.__check_for_templates)
154 LOG.debug("%s" % self.__class__.__name__)
156 self._gracefully_stop()
157 super(TranslatorService, self).terminate()
161 LOG.debug("%s" % self.__class__.__name__)