blob: 5c87795a37ba86bf485c0ffc409467f4c8755147 [file] [log] [blame]
Zsolt Harasztib71c2a02016-09-12 13:12:07 -07001#!/usr/bin/env python
2#
3# Copyright 2016 the original author or authors.
4#
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 Harasztid7c7c482016-09-13 00:45:38 -070021import os
Zsolt Haraszti361dc592016-09-25 22:25:23 -070022import sys
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070023import time
Zsolt Harasztid7c7c482016-09-13 00:45:38 -070024import yaml
Zsolt Harasztie060a7d2016-09-16 11:08:24 -070025from twisted.internet.defer import inlineCallbacks
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -070026
Zsolt Haraszti32dda552016-09-27 09:17:29 -070027base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
28sys.path.append(base_dir)
29sys.path.append(os.path.join(base_dir, '/voltha/core/protos/third_party'))
Zsolt Haraszti361dc592016-09-25 22:25:23 -070030
Zsolt Harasztieb435072016-09-23 17:10:49 -070031from voltha.coordinator import Coordinator
32from voltha.dockerhelpers import get_my_containers_name
33from voltha.nethelpers import get_my_primary_interface, get_my_primary_local_ipv4
34from voltha.northbound.grpc.grpc_server import VolthaGrpcServer
35from voltha.northbound.rest.health_check import init_rest_service
36from voltha.structlog_setup import setup_logging
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070037
38defs = dict(
39 consul=os.environ.get('CONSUL', 'localhost:8500'),
Zsolt Haraszti28e0f1c2016-09-13 23:55:43 -070040 instance_id=os.environ.get('INSTANCE_ID', os.environ.get('HOSTNAME', '1')),
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070041 config=os.environ.get('CONFIG', './voltha.yml'),
Zsolt Harasztide22bbc2016-09-14 15:27:33 -070042 interface=os.environ.get('INTERFACE', get_my_primary_interface()),
Zsolt Haraszti109db832016-09-16 16:32:36 -070043 internal_host_address=os.environ.get('INTERNAL_HOST_ADDRESS',
44 get_my_primary_local_ipv4()),
45 external_host_address=os.environ.get('EXTERNAL_HOST_ADDRESS',
46 get_my_primary_local_ipv4()),
Zsolt Harasztide22bbc2016-09-14 15:27:33 -070047 fluentd=os.environ.get('FLUENTD', None),
48 rest_port=os.environ.get('REST_PORT', 8880),
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070049)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -070050
51
52def parse_args():
53
54 parser = argparse.ArgumentParser()
55
Zsolt Haraszti109db832016-09-16 16:32:36 -070056 _help = ('Path to voltha.yml config file (default: %s). '
57 'If relative, it is relative to main.py of voltha.'
58 % defs['config'])
59 parser.add_argument('-c', '--config',
60 dest='config',
61 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070062 default=defs['config'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070063 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070064
Zsolt Haraszti109db832016-09-16 16:32:36 -070065 _help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
66 parser.add_argument(
67 '-C', '--consul', dest='consul', action='store',
68 default=defs['consul'],
69 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070070
Zsolt Haraszti109db832016-09-16 16:32:36 -070071 _help = ('<hostname> or <ip> at which Voltha is reachable from outside '
72 'the cluster (default: %s)' % defs['external_host_address'])
73 parser.add_argument('-E', '--external-host-address',
74 dest='external_host_address',
75 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070076 default=defs['external_host_address'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070077 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070078
Zsolt Haraszti109db832016-09-16 16:32:36 -070079 _help = ('<hostname>:<port> to fluentd server (default: %s). (If not '
80 'specified (None), the address from the config file is used'
81 % defs['fluentd'])
82 parser.add_argument('-F', '--fluentd',
83 dest='fluentd',
84 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070085 default=defs['fluentd'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070086 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070087
Zsolt Haraszti109db832016-09-16 16:32:36 -070088 _help = ('<hostname> or <ip> at which Voltha is reachable from inside the'
89 'cluster (default: %s)' % defs['internal_host_address'])
90 parser.add_argument('-H', '--internal-host-address',
91 dest='internal_host_address',
92 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070093 default=defs['internal_host_address'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070094 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070095
Zsolt Haraszti109db832016-09-16 16:32:36 -070096 _help = ('unique string id of this voltha instance (default: %s)'
Zsolt Haraszti86be6f12016-09-27 09:56:49 -070097 % defs['instance_id'])
Zsolt Haraszti109db832016-09-16 16:32:36 -070098 parser.add_argument('-i', '--instance-id',
99 dest='instance_id',
100 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700101 default=defs['instance_id'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700102 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700103
104 # TODO placeholder, not used yet
Zsolt Haraszti109db832016-09-16 16:32:36 -0700105 _help = 'ETH interface to send (default: %s)' % defs['interface']
106 parser.add_argument('-I', '--interface',
107 dest='interface',
108 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700109 default=defs['interface'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700110 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700111
Zsolt Haraszti109db832016-09-16 16:32:36 -0700112 _help = 'omit startup banner log lines'
113 parser.add_argument('-n', '--no-banner',
114 dest='no_banner',
115 action='store_true',
116 default=False,
117 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700118
Zsolt Haraszti109db832016-09-16 16:32:36 -0700119 _help = 'do not emit periodic heartbeat log messages'
120 parser.add_argument('-N', '--no-heartbeat',
121 dest='no_heartbeat',
122 action='store_true',
123 default=False,
124 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700125
Zsolt Haraszti109db832016-09-16 16:32:36 -0700126 _help = ('port number for the rest service (default: %d)'
127 % defs['rest_port'])
128 parser.add_argument('-R', '--rest-port',
129 dest='rest_port',
130 action='store',
131 type=int,
Zsolt Harasztide22bbc2016-09-14 15:27:33 -0700132 default=defs['rest_port'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700133 help=_help)
Zsolt Harasztide22bbc2016-09-14 15:27:33 -0700134
Zsolt Haraszti109db832016-09-16 16:32:36 -0700135 _help = "suppress debug and info logs"
136 parser.add_argument('-q', '--quiet',
137 dest='quiet',
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700138 action='count',
Zsolt Haraszti109db832016-09-16 16:32:36 -0700139 help=_help)
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -0700140
Zsolt Haraszti109db832016-09-16 16:32:36 -0700141 _help = 'enable verbose logging'
142 parser.add_argument('-v', '--verbose',
143 dest='verbose',
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700144 action='count',
Zsolt Haraszti109db832016-09-16 16:32:36 -0700145 help=_help)
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -0700146
Zsolt Haraszti109db832016-09-16 16:32:36 -0700147 _help = ('use docker container name as voltha instance id'
148 ' (overrides -i/--instance-id option)')
149 parser.add_argument('--instance-id-is-container-name',
150 dest='instance_id_is_container_name',
151 action='store_true',
152 default=False,
153 help=_help)
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700154
155 args = parser.parse_args()
156
157 # post-processing
158
159 if args.instance_id_is_container_name:
160 args.instance_id = get_my_containers_name()
161
162 return args
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700163
164
Zsolt Harasztid7c7c482016-09-13 00:45:38 -0700165def load_config(args):
166 path = args.config
167 if path.startswith('.'):
168 dir = os.path.dirname(os.path.abspath(__file__))
169 path = os.path.join(dir, path)
170 path = os.path.abspath(path)
171 with open(path) as fd:
172 config = yaml.load(fd)
173 return config
174
175
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700176def print_banner(log):
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700177 log.info(' _ ______ __ ________ _____ ')
178 log.info('| | / / __ \/ / /_ __/ / / / |')
179 log.info('| | / / / / / / / / / /_/ / /| |')
180 log.info('| |/ / /_/ / /___/ / / __ / ___ |')
181 log.info('|___/\____/_____/_/ /_/ /_/_/ |_|')
Zsolt Haraszti59b7a882016-09-12 14:42:59 -0700182 log.info('(to stop: press Ctrl-C)')
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700183
184
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700185class Main(object):
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700186
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700187 def __init__(self):
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700188
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700189 self.args = args = parse_args()
190 self.config = load_config(args)
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700191
192 verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
Zsolt Haraszti109db832016-09-16 16:32:36 -0700193 self.log = setup_logging(self.config.get('logging', {}),
194 args.instance_id,
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700195 verbosity_adjust=verbosity_adjust,
Zsolt Haraszti109db832016-09-16 16:32:36 -0700196 fluentd=args.fluentd)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700197
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700198 # components
199 self.coordinator = None
Zsolt Harasztieb435072016-09-23 17:10:49 -0700200 self.grpc_server = None
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700201
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700202 if not args.no_banner:
203 print_banner(self.log)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700204
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700205 if not args.no_heartbeat:
206 self.start_heartbeat()
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700207
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700208 self.startup_components()
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700209
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700210 def start(self):
211 self.start_reactor() # will not return except Keyboard interrupt
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700212
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700213 def startup_components(self):
214 self.log.info('starting-internal-components')
215 self.coordinator = Coordinator(
216 internal_host_address=self.args.internal_host_address,
217 external_host_address=self.args.external_host_address,
218 rest_port=self.args.rest_port,
219 instance_id=self.args.instance_id,
220 consul=self.args.consul)
221 init_rest_service(self.args.rest_port)
Zsolt Harasztieb435072016-09-23 17:10:49 -0700222
223 self.grpc_server = VolthaGrpcServer().run()
224
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700225 self.log.info('started-internal-services')
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700226
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700227 @inlineCallbacks
228 def shutdown_components(self):
229 """Execute before the reactor is shut down"""
230 self.log.info('exiting-on-keyboard-interrupt')
Zsolt Harasztieb435072016-09-23 17:10:49 -0700231 if self.coordinator is not None:
232 yield self.coordinator.shutdown()
233 if self.grpc_server is not None:
234 yield self.grpc_server.shutdown()
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700235
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700236 def start_reactor(self):
237 from twisted.internet import reactor
Zsolt Haraszti109db832016-09-16 16:32:36 -0700238 reactor.callWhenRunning(
239 lambda: self.log.info('twisted-reactor-started'))
240 reactor.addSystemEventTrigger('before', 'shutdown',
241 self.shutdown_components)
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700242 reactor.run()
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700243
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700244 def start_heartbeat(self):
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700245
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700246 t0 = time.time()
247 t0s = time.ctime(t0)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700248
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700249 def heartbeat():
250 self.log.debug(status='up', since=t0s, uptime=time.time() - t0)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700251
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700252 from twisted.internet.task import LoopingCall
253 lc = LoopingCall(heartbeat)
254 lc.start(10)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700255
256
257if __name__ == '__main__':
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700258 Main().start()