blob: 9485b1887360187c2437a475282e7ecda6401cae [file] [log] [blame]
Zsolt Harasztib71c2a02016-09-12 13:12:07 -07001#!/usr/bin/env python
2#
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08003# Copyright 2017 the original author or authors.
Zsolt Harasztib71c2a02016-09-12 13:12:07 -07004#
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
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
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.
16#
17
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -070018"""Virtual OLT Hardware Abstraction main entry point"""
Zsolt Harasztib71c2a02016-09-12 13:12:07 -070019
20import argparse
Zsolt Harasztib5d72f12017-01-15 20:44:02 -080021import arrow
Zsolt Harasztid7c7c482016-09-13 00:45:38 -070022import os
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070023import time
Zsolt Haraszti023ea7c2016-10-16 19:30:34 -070024
Zsolt Harasztid7c7c482016-09-13 00:45:38 -070025import yaml
Zsolt Haraszti89a27302016-12-08 16:53:06 -080026from simplejson import dumps
Zsolt Harasztie060a7d2016-09-16 11:08:24 -070027from twisted.internet.defer import inlineCallbacks
Zsolt Harasztib5d72f12017-01-15 20:44:02 -080028from twisted.internet.task import LoopingCall
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -080029from zope.interface import implementer
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -070030
Zsolt Haraszti3bfff662016-12-14 23:41:49 -080031from common.event_bus import EventBusClient
32from common.manhole import Manhole
khenaidoocbe30832017-08-25 10:43:27 -040033from common.structlog_setup import setup_logging, update_logging
Zsolt Haraszti023ea7c2016-10-16 19:30:34 -070034from common.utils.dockerhelpers import get_my_containers_name
35from common.utils.nethelpers import get_my_primary_interface, \
Khen Nursimulu441dedd2016-10-05 14:44:26 -070036 get_my_primary_local_ipv4
Zsolt Haraszti7eeb2b32016-11-06 14:04:55 -080037from voltha.adapters.loader import AdapterLoader
Zsolt Harasztid70cd4d2016-11-03 23:23:36 -070038from voltha.coordinator import Coordinator
Richard Jankowski8b277c22017-12-19 09:49:27 -050039from voltha.coordinator_etcd import CoordinatorEtcd
Zsolt Harasztidafefe12016-11-14 21:29:58 -080040from voltha.core.core import VolthaCore
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080041from voltha.core.config.config_backend import load_backend
Zsolt Haraszti99509d32016-12-10 16:41:45 -080042from voltha.northbound.diagnostics import Diagnostics
Zsolt Harasztieb435072016-09-23 17:10:49 -070043from voltha.northbound.grpc.grpc_server import VolthaGrpcServer
khenb95fe9a2016-10-05 11:15:25 -070044from voltha.northbound.kafka.kafka_proxy import KafkaProxy, get_kafka_proxy
Zsolt Harasztid70cd4d2016-11-03 23:23:36 -070045from voltha.northbound.rest.health_check import init_rest_service
Zsolt Haraszti66862032016-11-28 14:28:39 -080046from voltha.protos.common_pb2 import LogLevel
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -080047from voltha.registry import registry, IComponent
Zsolt Haraszti89a27302016-12-08 16:53:06 -080048from common.frameio.frameio import FrameIOManager
Jonathan Hartda93ac62018-05-01 11:25:29 -070049from packaging.version import Version
khenb95fe9a2016-10-05 11:15:25 -070050
khenaidoo032d3302017-06-09 14:50:04 -040051
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070052defs = dict(
Jonathan Hartda93ac62018-05-01 11:25:29 -070053 version_file='./VERSION',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070054 config=os.environ.get('CONFIG', './voltha.yml'),
Zack Williams55b456e2018-11-03 20:08:53 -070055 logconfig=os.environ.get('LOGCONFIG', './logconfig.yml'),
Richard Jankowski4ea26632018-05-14 17:45:38 -040056 container_name_regex=os.environ.get('CORE_NUMBER_EXTRACTOR', '^.*\.([0-9]+)\..*$'),
Zsolt Haraszti553826c2016-09-27 10:24:27 -070057 consul=os.environ.get('CONSUL', 'localhost:8500'),
Richard Jankowski8b277c22017-12-19 09:49:27 -050058 etcd=os.environ.get('ETCD', 'localhost:2379'),
khenaidoo26a8c012017-07-07 18:25:47 -040059 inter_core_subnet=os.environ.get('INTER_CORE_SUBNET', None),
60 pon_subnet=os.environ.get('PON_SUBNET', None),
61 external_host_address=os.environ.get('EXTERNAL_HOST_ADDRESS',
62 get_my_primary_local_ipv4()),
Zsolt Haraszti553826c2016-09-27 10:24:27 -070063 grpc_port=os.environ.get('GRPC_PORT', 50055),
64 instance_id=os.environ.get('INSTANCE_ID', os.environ.get('HOSTNAME', '1')),
khenaidoo26a8c012017-07-07 18:25:47 -040065 internal_host_address=os.environ.get('INTERNAL_HOST_ADDRESS',
66 get_my_primary_local_ipv4()),
Zsolt Haraszti553826c2016-09-27 10:24:27 -070067 interface=os.environ.get('INTERFACE', get_my_primary_interface()),
Zsolt Harasztide22bbc2016-09-14 15:27:33 -070068 rest_port=os.environ.get('REST_PORT', 8880),
khenb95fe9a2016-10-05 11:15:25 -070069 kafka=os.environ.get('KAFKA', 'localhost:9092'),
Zsolt Haraszti3bfff662016-12-14 23:41:49 -080070 manhole_port=os.environ.get('MANHOLE_PORT', 12222),
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -080071 backend=os.environ.get('BACKEND', 'none'),
Stephane Barbarie35595062018-02-08 08:34:39 -050072 ponsim_comm=os.environ.get('PONSIM_COMM', 'frameio')
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070073)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -070074
75
76def parse_args():
Zsolt Harasztib71c2a02016-09-12 13:12:07 -070077 parser = argparse.ArgumentParser()
78
Zsolt Haraszti109db832016-09-16 16:32:36 -070079 _help = ('Path to voltha.yml config file (default: %s). '
80 'If relative, it is relative to main.py of voltha.'
81 % defs['config'])
82 parser.add_argument('-c', '--config',
83 dest='config',
84 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070085 default=defs['config'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070086 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070087
Zack Williams55b456e2018-11-03 20:08:53 -070088 _help = ('Path to logconfig.yml config file (default: %s). '
89 'If relative, it is relative to main.py of voltha.'
90 % defs['logconfig'])
91 parser.add_argument('-l', '--logconfig',
92 dest='logconfig',
93 action='store',
94 default=defs['logconfig'],
95 help=_help)
96
Richard Jankowski4ea26632018-05-14 17:45:38 -040097 _help = 'Regular expression for extracting core number from container name (default: %s)' % defs['container_name_regex']
98 parser.add_argument(
99 '-X', '--core-number-extractor', dest='container_name_regex', action='store',
100 default=defs['container_name_regex'],
101 help=_help)
102
Zsolt Haraszti109db832016-09-16 16:32:36 -0700103 _help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
104 parser.add_argument(
105 '-C', '--consul', dest='consul', action='store',
106 default=defs['consul'],
107 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700108
Richard Jankowski8b277c22017-12-19 09:49:27 -0500109 _help = '<hostname>:<port> to etcd server (default: %s)' % defs['etcd']
110 parser.add_argument(
111 '-e', '--etcd', dest='etcd', action='store',
112 default=defs['etcd'],
113 help=_help)
khenaidoo26a8c012017-07-07 18:25:47 -0400114
115 _help = ('<inter_core_subnet> is the subnet connecting all the voltha '
116 'instances in a cluster (default: %s)' % defs['inter_core_subnet'])
117 parser.add_argument('-V', '--inter-core-subnet',
118 dest='inter_core_subnet',
119 action='store',
120 default=defs['inter_core_subnet'],
121 help=_help)
122
123 _help = ('<pon subnet> is the subnet connecting the voltha instances'
124 'with the PON network (default: %s)' % defs['pon_subnet'])
125 parser.add_argument('-P', '--pon-subnet',
126 dest='pon_subnet',
127 action='store',
128 default=defs['pon_subnet'],
129 help=_help)
130
Zsolt Haraszti109db832016-09-16 16:32:36 -0700131 _help = ('<hostname> or <ip> at which Voltha is reachable from outside '
132 'the cluster (default: %s)' % defs['external_host_address'])
133 parser.add_argument('-E', '--external-host-address',
134 dest='external_host_address',
135 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700136 default=defs['external_host_address'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700137 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700138
Zsolt Haraszti553826c2016-09-27 10:24:27 -0700139 _help = ('port number of the GRPC service exposed by voltha (default: %s)'
140 % defs['grpc_port'])
141 parser.add_argument('-g', '--grpc-port',
142 dest='grpc_port',
143 action='store',
144 default=defs['grpc_port'],
145 help=_help)
Khen Nursimulu441dedd2016-10-05 14:44:26 -0700146
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700147
Zsolt Haraszti109db832016-09-16 16:32:36 -0700148 _help = ('<hostname> or <ip> at which Voltha is reachable from inside the'
149 'cluster (default: %s)' % defs['internal_host_address'])
150 parser.add_argument('-H', '--internal-host-address',
151 dest='internal_host_address',
152 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700153 default=defs['internal_host_address'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700154 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700155
Zsolt Haraszti109db832016-09-16 16:32:36 -0700156 _help = ('unique string id of this voltha instance (default: %s)'
Zsolt Haraszti86be6f12016-09-27 09:56:49 -0700157 % defs['instance_id'])
Zsolt Haraszti109db832016-09-16 16:32:36 -0700158 parser.add_argument('-i', '--instance-id',
159 dest='instance_id',
160 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700161 default=defs['instance_id'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700162 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700163
khenaidooccc42252017-07-06 23:00:49 -0400164 _help = 'ETH interface to recieve (default: %s)' % defs['interface']
Zsolt Haraszti109db832016-09-16 16:32:36 -0700165 parser.add_argument('-I', '--interface',
166 dest='interface',
167 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700168 default=defs['interface'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700169 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700170
Zsolt Haraszti3bfff662016-12-14 23:41:49 -0800171 _help = 'open ssh manhole at given port'
172 parser.add_argument('-m', '--manhole-port',
173 dest='manhole_port',
174 action='store',
175 type=int,
176 default=None,
177 help=_help)
178
Zsolt Haraszti109db832016-09-16 16:32:36 -0700179 _help = 'omit startup banner log lines'
180 parser.add_argument('-n', '--no-banner',
181 dest='no_banner',
182 action='store_true',
183 default=False,
184 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700185
Zsolt Haraszti109db832016-09-16 16:32:36 -0700186 _help = 'do not emit periodic heartbeat log messages'
187 parser.add_argument('-N', '--no-heartbeat',
188 dest='no_heartbeat',
189 action='store_true',
190 default=False,
191 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700192
Zsolt Haraszti109db832016-09-16 16:32:36 -0700193 _help = ('port number for the rest service (default: %d)'
194 % defs['rest_port'])
195 parser.add_argument('-R', '--rest-port',
196 dest='rest_port',
197 action='store',
198 type=int,
Zsolt Harasztide22bbc2016-09-14 15:27:33 -0700199 default=defs['rest_port'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700200 help=_help)
Zsolt Harasztide22bbc2016-09-14 15:27:33 -0700201
Zsolt Haraszti109db832016-09-16 16:32:36 -0700202 _help = "suppress debug and info logs"
203 parser.add_argument('-q', '--quiet',
204 dest='quiet',
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700205 action='count',
Zsolt Haraszti109db832016-09-16 16:32:36 -0700206 help=_help)
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -0700207
Zsolt Haraszti109db832016-09-16 16:32:36 -0700208 _help = 'enable verbose logging'
209 parser.add_argument('-v', '--verbose',
210 dest='verbose',
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700211 action='count',
Zsolt Haraszti109db832016-09-16 16:32:36 -0700212 help=_help)
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -0700213
Zsolt Haraszti109db832016-09-16 16:32:36 -0700214 _help = ('use docker container name as voltha instance id'
215 ' (overrides -i/--instance-id option)')
216 parser.add_argument('--instance-id-is-container-name',
217 dest='instance_id_is_container_name',
218 action='store_true',
219 default=False,
220 help=_help)
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700221
khenb95fe9a2016-10-05 11:15:25 -0700222 _help = ('<hostname>:<port> of the kafka broker (default: %s). (If not '
223 'specified (None), the address from the config file is used'
224 % defs['kafka'])
225 parser.add_argument('-K', '--kafka',
226 dest='kafka',
227 action='store',
228 default=defs['kafka'],
229 help=_help)
230
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -0800231 _help = 'backend to use for config persitence'
232 parser.add_argument('-b', '--backend',
233 default=defs['backend'],
Richard Jankowski8b277c22017-12-19 09:49:27 -0500234 choices=['none', 'consul', 'etcd'],
Ryan Van Gilder5a0ab622017-03-01 16:39:25 -0800235 help=_help)
236
Stephane Barbarie35595062018-02-08 08:34:39 -0500237 _help = "Communication mechanism to use with PON simulator"
238 parser.add_argument('-S', '--ponsim-comm',
239 dest='ponsim_comm',
240 default=defs['ponsim_comm'],
241 choices=['frameio', 'grpc'],
242 help=_help)
243
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700244 args = parser.parse_args()
245
246 # post-processing
247
248 if args.instance_id_is_container_name:
249 args.instance_id = get_my_containers_name()
250
Jonathan Hartda93ac62018-05-01 11:25:29 -0700251 """
252 The container external, internal IP and PON interface needs to be
253 set based on the subnet data. At this time the internal IP is not used.
khenaidoo26a8c012017-07-07 18:25:47 -0400254 The external IP is used for inter-core communications. If the subnets are
255 set then they take precedence over the other relevant arguments (
256 external and internal host as well as interface
257 """
258 if args.inter_core_subnet:
259 m_ip = get_my_primary_local_ipv4(inter_core_subnet=args.inter_core_subnet)
khenaidooccc42252017-07-06 23:00:49 -0400260 args.external_host_address = m_ip
khenaidooccc42252017-07-06 23:00:49 -0400261 args.internal_host_address = m_ip
262
khenaidoo26a8c012017-07-07 18:25:47 -0400263 if args.pon_subnet:
264 args.interface = get_my_primary_interface(args.pon_subnet)
265
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700266 return args
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700267
268
Zack Williams55b456e2018-11-03 20:08:53 -0700269def load_config(args, configname='config'):
270 argdict = vars(args)
271 path = argdict[configname]
Zsolt Harasztid7c7c482016-09-13 00:45:38 -0700272 if path.startswith('.'):
273 dir = os.path.dirname(os.path.abspath(__file__))
274 path = os.path.join(dir, path)
275 path = os.path.abspath(path)
276 with open(path) as fd:
277 config = yaml.load(fd)
278 return config
279
280
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700281def print_banner(log):
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700282 log.info(' _ ______ __ ________ _____ ')
283 log.info('| | / / __ \/ / /_ __/ / / / |')
284 log.info('| | / / / / / / / / / /_/ / /| |')
285 log.info('| |/ / /_/ / /___/ / / __ / ___ |')
286 log.info('|___/\____/_____/_/ /_/ /_/_/ |_|')
Zsolt Haraszti59b7a882016-09-12 14:42:59 -0700287 log.info('(to stop: press Ctrl-C)')
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700288
289
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800290@implementer(IComponent)
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700291class Main(object):
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800292
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700293 def __init__(self):
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700294
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700295 self.args = args = parse_args()
296 self.config = load_config(args)
Zack Williams55b456e2018-11-03 20:08:53 -0700297 self.logconfig = load_config(args, 'logconfig')
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700298
299 verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
Zack Williams55b456e2018-11-03 20:08:53 -0700300 self.log = setup_logging(self.logconfig,
Zsolt Haraszti109db832016-09-16 16:32:36 -0700301 args.instance_id,
Zack Williams18357ed2018-11-14 10:41:08 -0700302 verbosity_adjust=verbosity_adjust,
303 cache_on_use=True)
Richard Jankowski4ea26632018-05-14 17:45:38 -0400304 self.log.info('core-number-extractor', regex=args.container_name_regex)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700305
Jonathan Hartda93ac62018-05-01 11:25:29 -0700306 self.voltha_version = self.get_version()
Zack Williams18357ed2018-11-14 10:41:08 -0700307 self.log.info('VOLTHA version is %s' % self.voltha_version)
Jonathan Hartda93ac62018-05-01 11:25:29 -0700308
Rouzbahan Rashidi-Tabrizi1c3eba82016-10-27 21:47:18 -0400309 # configurable variables from voltha.yml file
310 #self.configurable_vars = self.config.get('Constants', {})
311
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700312 if not args.no_banner:
313 print_banner(self.log)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700314
Richard Jankowski4ea26632018-05-14 17:45:38 -0400315 # Create a unique instance id using the passed-in instance id and
khenaidoo032d3302017-06-09 14:50:04 -0400316 # UTC timestamp
317 current_time = arrow.utcnow().timestamp
318 self.instance_id = self.args.instance_id + '_' + str(current_time)
319
320 # Every voltha instance is given a core_storage id where the
321 # instance data is stored
322 self.core_store_id = None
323
khenb95fe9a2016-10-05 11:15:25 -0700324 self.startup_components()
325
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700326 if not args.no_heartbeat:
327 self.start_heartbeat()
khenaidoo032d3302017-06-09 14:50:04 -0400328 self.start_kafka_heartbeat(self.instance_id)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700329
Zsolt Haraszti3bfff662016-12-14 23:41:49 -0800330 self.manhole = None
331
Jonathan Hartda93ac62018-05-01 11:25:29 -0700332 def get_version(self):
333 path = defs['version_file']
334 if not path.startswith('/'):
335 dir = os.path.dirname(os.path.abspath(__file__))
336 path = os.path.join(dir, path)
337
338 path = os.path.abspath(path)
339 version_file = open(path, 'r')
340 v = version_file.read()
341
342 # Use Version to validate the version string - exception will be raised
343 # if the version is invalid
344 Version(v)
345
346 version_file.close()
347 return v
348
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700349 def start(self):
350 self.start_reactor() # will not return except Keyboard interrupt
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700351
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800352 def stop(self):
353 pass
354
355 def get_args(self):
356 """Allow access to command line args"""
357 return self.args
358
359 def get_config(self):
360 """Allow access to content of config file"""
361 return self.config
362
Zsolt Haraszti7eeb2b32016-11-06 14:04:55 -0800363 @inlineCallbacks
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700364 def startup_components(self):
Khen Nursimulu3c74d3b2016-11-08 15:14:01 -0800365 try:
khenaidooccc42252017-07-06 23:00:49 -0400366 self.log.info('starting-internal-components',
367 internal_host=self.args.internal_host_address,
khenaidoo26a8c012017-07-07 18:25:47 -0400368 external_host=self.args.external_host_address,
369 interface=self.args.interface,
Richard Jankowski8b277c22017-12-19 09:49:27 -0500370 consul=self.args.consul,
371 etcd=self.args.etcd)
Zsolt Harasztidafefe12016-11-14 21:29:58 -0800372
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800373 registry.register('main', self)
374
Richard Jankowski8b277c22017-12-19 09:49:27 -0500375 if self.args.backend == 'consul':
376 yield registry.register(
377 'coordinator',
378 Coordinator(
379 internal_host_address=self.args.internal_host_address,
380 external_host_address=self.args.external_host_address,
381 rest_port=self.args.rest_port,
382 instance_id=self.instance_id,
383 config=self.config,
Richard Jankowski4ea26632018-05-14 17:45:38 -0400384 consul=self.args.consul,
385 container_name_regex=self.args.container_name_regex)
Richard Jankowski8b277c22017-12-19 09:49:27 -0500386 ).start()
387 elif self.args.backend == 'etcd':
388 yield registry.register(
389 'coordinator',
390 CoordinatorEtcd(
391 internal_host_address=self.args.internal_host_address,
392 external_host_address=self.args.external_host_address,
393 rest_port=self.args.rest_port,
394 instance_id=self.instance_id,
395 config=self.config,
Richard Jankowski4ea26632018-05-14 17:45:38 -0400396 etcd=self.args.etcd,
397 container_name_regex=self.args.container_name_regex)
Richard Jankowski8b277c22017-12-19 09:49:27 -0500398 ).start()
Zsolt Harasztidafefe12016-11-14 21:29:58 -0800399
khenaidoo032d3302017-06-09 14:50:04 -0400400 self.log.info('waiting-for-config-assignment')
401
402 # Wait until we get a config id before we proceed
403 self.core_store_id, store_prefix = \
404 yield registry('coordinator').get_core_store_id_and_prefix()
405
406 self.log.info('store-id', core_store_id=self.core_store_id)
Zsolt Harasztieb435072016-09-23 17:10:49 -0700407
khenaidoocbe30832017-08-25 10:43:27 -0400408 # Update the logger to output the vcore id.
409 self.log = update_logging(instance_id=self.instance_id, vcore_id=self.core_store_id)
410
Zsolt Haraszti66862032016-11-28 14:28:39 -0800411 yield registry.register(
412 'grpc_server',
413 VolthaGrpcServer(self.args.grpc_port)
414 ).start()
Zsolt Harasztieb435072016-09-23 17:10:49 -0700415
Zsolt Haraszti66862032016-11-28 14:28:39 -0800416 yield registry.register(
khenaidoo032d3302017-06-09 14:50:04 -0400417 'core',
418 VolthaCore(
419 instance_id=self.instance_id,
420 core_store_id = self.core_store_id,
khenaidoo08d48d22017-06-29 19:42:49 -0400421 grpc_port=self.args.grpc_port,
Jonathan Hartda93ac62018-05-01 11:25:29 -0700422 version=self.voltha_version,
khenaidoo032d3302017-06-09 14:50:04 -0400423 log_level=LogLevel.INFO
424 )
425 ).start(config_backend=load_backend(store_id=self.core_store_id,
426 store_prefix=store_prefix,
427 args=self.args))
428
429 init_rest_service(self.args.rest_port)
430
431 yield registry.register(
Zsolt Haraszti66862032016-11-28 14:28:39 -0800432 'kafka_proxy',
Zsolt Haraszti99509d32016-12-10 16:41:45 -0800433 KafkaProxy(
434 self.args.consul,
435 self.args.kafka,
436 config=self.config.get('kafka-proxy', {})
437 )
Zsolt Haraszti66862032016-11-28 14:28:39 -0800438 ).start()
439
440 yield registry.register(
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800441 'frameio',
442 FrameIOManager()
443 ).start()
444
445 yield registry.register(
Zsolt Haraszti66862032016-11-28 14:28:39 -0800446 'adapter_loader',
447 AdapterLoader(config=self.config.get('adapter_loader', {}))
448 ).start()
khenb95fe9a2016-10-05 11:15:25 -0700449
Zsolt Haraszti99509d32016-12-10 16:41:45 -0800450 yield registry.register(
451 'diag',
452 Diagnostics(config=self.config.get('diagnostics', {}))
453 ).start()
454
Zsolt Haraszti3bfff662016-12-14 23:41:49 -0800455 if self.args.manhole_port is not None:
456 self.start_manhole(self.args.manhole_port)
457
khenaidoo032d3302017-06-09 14:50:04 -0400458 # Now that all components are loaded, in the scenario where this
459 # voltha instance is picking up an existing set of data (from a
460 # voltha instance that dies/stopped) then we need to setup this
461 # instance from where the previous one left
462
463 yield registry('core').reconcile_data()
464
khenaidoocbe30832017-08-25 10:43:27 -0400465 # Now that the data is in memory and the reconcile process
466 # within the core has completed (the reconciliation may still be
467 # in progress with the adapters) we expose the NBI of voltha core
468 yield registry('core').register_grpc_service()
469
Khen Nursimulu3c74d3b2016-11-08 15:14:01 -0800470 self.log.info('started-internal-services')
471
472 except Exception as e:
khenaidoo032d3302017-06-09 14:50:04 -0400473 self.log.exception('Failure-to-start-all-components', e=e)
Khen Nursimulu3c74d3b2016-11-08 15:14:01 -0800474
Zsolt Haraszti3bfff662016-12-14 23:41:49 -0800475 def start_manhole(self, port):
476 self.manhole = Manhole(
477 port,
478 pws=dict(admin='adminpw'),
479 eventbus = EventBusClient(),
480 **registry.components
481 )
482
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700483 @inlineCallbacks
484 def shutdown_components(self):
485 """Execute before the reactor is shut down"""
486 self.log.info('exiting-on-keyboard-interrupt')
Zsolt Harasztidafefe12016-11-14 21:29:58 -0800487 for component in reversed(registry.iterate()):
488 yield component.stop()
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700489
Zsolt Haraszti3300f742017-01-09 01:14:20 -0800490 import threading
491 self.log.info('THREADS:')
492 main_thread = threading.current_thread()
493 for t in threading.enumerate():
494 if t is main_thread:
495 continue
496 if not t.isDaemon():
497 continue
498 self.log.info('joining thread {} {}'.format(
499 t.getName(), "daemon" if t.isDaemon() else "not-daemon"))
500 t.join()
501
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700502 def start_reactor(self):
503 from twisted.internet import reactor
Zsolt Haraszti109db832016-09-16 16:32:36 -0700504 reactor.callWhenRunning(
505 lambda: self.log.info('twisted-reactor-started'))
506 reactor.addSystemEventTrigger('before', 'shutdown',
507 self.shutdown_components)
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700508 reactor.run()
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700509
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700510 def start_heartbeat(self):
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700511
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700512 t0 = time.time()
513 t0s = time.ctime(t0)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700514
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700515 def heartbeat():
516 self.log.debug(status='up', since=t0s, uptime=time.time() - t0)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700517
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700518 lc = LoopingCall(heartbeat)
519 lc.start(10)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700520
khenb95fe9a2016-10-05 11:15:25 -0700521 # Temporary function to send a heartbeat message to the external kafka
522 # broker
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800523 def start_kafka_heartbeat(self, instance_id):
khenb95fe9a2016-10-05 11:15:25 -0700524 # For heartbeat we will send a message to a specific "voltha-heartbeat"
525 # topic. The message is a protocol buf
526 # message
Zsolt Harasztib5d72f12017-01-15 20:44:02 -0800527 message = dict(
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800528 type='heartbeat',
529 voltha_instance=instance_id,
530 ip=get_my_primary_local_ipv4()
Zsolt Harasztib5d72f12017-01-15 20:44:02 -0800531 )
532 topic = "voltha.heartbeat"
khenb95fe9a2016-10-05 11:15:25 -0700533
Zsolt Harasztib5d72f12017-01-15 20:44:02 -0800534 def send_msg():
Rouzbahan Rashidi-Tabrizi380dcb32017-03-23 18:01:02 -0400535 try:
536 kafka_proxy = get_kafka_proxy()
537 if kafka_proxy and not kafka_proxy.is_faulty():
538 self.log.debug('kafka-proxy-available')
539 message['ts'] = arrow.utcnow().timestamp
540 self.log.debug('start-kafka-heartbeat')
541 kafka_proxy.send_message(topic, dumps(message))
542 else:
543 self.log.error('kafka-proxy-unavailable')
544 except Exception, e:
545 self.log.exception('failed-sending-message-heartbeat', e=e)
Zsolt Harasztib5d72f12017-01-15 20:44:02 -0800546
Rouzbahan Rashidi-Tabrizi380dcb32017-03-23 18:01:02 -0400547 try:
Zsolt Harasztib5d72f12017-01-15 20:44:02 -0800548 lc = LoopingCall(send_msg)
Khen Nursimulu3c74d3b2016-11-08 15:14:01 -0800549 lc.start(10)
Rouzbahan Rashidi-Tabrizi380dcb32017-03-23 18:01:02 -0400550 except Exception, e:
551 self.log.exception('failed-kafka-heartbeat', e=e)
Khen Nursimulu441dedd2016-10-05 14:44:26 -0700552
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800553
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700554if __name__ == '__main__':
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700555 Main().start()