blob: a3badea88a08b696eed6cd5d8979aa231f2e1d19 [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(
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070039 config=os.environ.get('CONFIG', './voltha.yml'),
Zsolt Haraszti553826c2016-09-27 10:24:27 -070040 consul=os.environ.get('CONSUL', 'localhost:8500'),
Zsolt Haraszti109db832016-09-16 16:32:36 -070041 external_host_address=os.environ.get('EXTERNAL_HOST_ADDRESS',
42 get_my_primary_local_ipv4()),
Zsolt Harasztide22bbc2016-09-14 15:27:33 -070043 fluentd=os.environ.get('FLUENTD', None),
Zsolt Haraszti553826c2016-09-27 10:24:27 -070044 grpc_port=os.environ.get('GRPC_PORT', 50055),
45 instance_id=os.environ.get('INSTANCE_ID', os.environ.get('HOSTNAME', '1')),
46 internal_host_address=os.environ.get('INTERNAL_HOST_ADDRESS',
47 get_my_primary_local_ipv4()),
48 interface=os.environ.get('INTERFACE', get_my_primary_interface()),
Zsolt Harasztide22bbc2016-09-14 15:27:33 -070049 rest_port=os.environ.get('REST_PORT', 8880),
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070050)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -070051
52
53def parse_args():
54
55 parser = argparse.ArgumentParser()
56
Zsolt Haraszti109db832016-09-16 16:32:36 -070057 _help = ('Path to voltha.yml config file (default: %s). '
58 'If relative, it is relative to main.py of voltha.'
59 % defs['config'])
60 parser.add_argument('-c', '--config',
61 dest='config',
62 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070063 default=defs['config'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070064 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070065
Zsolt Haraszti109db832016-09-16 16:32:36 -070066 _help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
67 parser.add_argument(
68 '-C', '--consul', dest='consul', action='store',
69 default=defs['consul'],
70 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070071
Zsolt Haraszti109db832016-09-16 16:32:36 -070072 _help = ('<hostname> or <ip> at which Voltha is reachable from outside '
73 'the cluster (default: %s)' % defs['external_host_address'])
74 parser.add_argument('-E', '--external-host-address',
75 dest='external_host_address',
76 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070077 default=defs['external_host_address'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070078 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070079
Zsolt Haraszti553826c2016-09-27 10:24:27 -070080 _help = ('port number of the GRPC service exposed by voltha (default: %s)'
81 % defs['grpc_port'])
82 parser.add_argument('-g', '--grpc-port',
83 dest='grpc_port',
84 action='store',
85 default=defs['grpc_port'],
86 help=_help)
87
Zsolt Haraszti109db832016-09-16 16:32:36 -070088 _help = ('<hostname>:<port> to fluentd server (default: %s). (If not '
89 'specified (None), the address from the config file is used'
90 % defs['fluentd'])
91 parser.add_argument('-F', '--fluentd',
92 dest='fluentd',
93 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070094 default=defs['fluentd'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070095 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070096
Zsolt Haraszti109db832016-09-16 16:32:36 -070097 _help = ('<hostname> or <ip> at which Voltha is reachable from inside the'
98 'cluster (default: %s)' % defs['internal_host_address'])
99 parser.add_argument('-H', '--internal-host-address',
100 dest='internal_host_address',
101 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700102 default=defs['internal_host_address'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700103 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700104
Zsolt Haraszti109db832016-09-16 16:32:36 -0700105 _help = ('unique string id of this voltha instance (default: %s)'
Zsolt Haraszti86be6f12016-09-27 09:56:49 -0700106 % defs['instance_id'])
Zsolt Haraszti109db832016-09-16 16:32:36 -0700107 parser.add_argument('-i', '--instance-id',
108 dest='instance_id',
109 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700110 default=defs['instance_id'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700111 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700112
113 # TODO placeholder, not used yet
Zsolt Haraszti109db832016-09-16 16:32:36 -0700114 _help = 'ETH interface to send (default: %s)' % defs['interface']
115 parser.add_argument('-I', '--interface',
116 dest='interface',
117 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700118 default=defs['interface'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700119 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700120
Zsolt Haraszti109db832016-09-16 16:32:36 -0700121 _help = 'omit startup banner log lines'
122 parser.add_argument('-n', '--no-banner',
123 dest='no_banner',
124 action='store_true',
125 default=False,
126 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700127
Zsolt Haraszti109db832016-09-16 16:32:36 -0700128 _help = 'do not emit periodic heartbeat log messages'
129 parser.add_argument('-N', '--no-heartbeat',
130 dest='no_heartbeat',
131 action='store_true',
132 default=False,
133 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700134
Zsolt Haraszti109db832016-09-16 16:32:36 -0700135 _help = ('port number for the rest service (default: %d)'
136 % defs['rest_port'])
137 parser.add_argument('-R', '--rest-port',
138 dest='rest_port',
139 action='store',
140 type=int,
Zsolt Harasztide22bbc2016-09-14 15:27:33 -0700141 default=defs['rest_port'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700142 help=_help)
Zsolt Harasztide22bbc2016-09-14 15:27:33 -0700143
Zsolt Haraszti109db832016-09-16 16:32:36 -0700144 _help = "suppress debug and info logs"
145 parser.add_argument('-q', '--quiet',
146 dest='quiet',
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700147 action='count',
Zsolt Haraszti109db832016-09-16 16:32:36 -0700148 help=_help)
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -0700149
Zsolt Haraszti109db832016-09-16 16:32:36 -0700150 _help = 'enable verbose logging'
151 parser.add_argument('-v', '--verbose',
152 dest='verbose',
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700153 action='count',
Zsolt Haraszti109db832016-09-16 16:32:36 -0700154 help=_help)
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -0700155
Zsolt Haraszti109db832016-09-16 16:32:36 -0700156 _help = ('use docker container name as voltha instance id'
157 ' (overrides -i/--instance-id option)')
158 parser.add_argument('--instance-id-is-container-name',
159 dest='instance_id_is_container_name',
160 action='store_true',
161 default=False,
162 help=_help)
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700163
164 args = parser.parse_args()
165
166 # post-processing
167
168 if args.instance_id_is_container_name:
169 args.instance_id = get_my_containers_name()
170
171 return args
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700172
173
Zsolt Harasztid7c7c482016-09-13 00:45:38 -0700174def load_config(args):
175 path = args.config
176 if path.startswith('.'):
177 dir = os.path.dirname(os.path.abspath(__file__))
178 path = os.path.join(dir, path)
179 path = os.path.abspath(path)
180 with open(path) as fd:
181 config = yaml.load(fd)
182 return config
183
184
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700185def print_banner(log):
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700186 log.info(' _ ______ __ ________ _____ ')
187 log.info('| | / / __ \/ / /_ __/ / / / |')
188 log.info('| | / / / / / / / / / /_/ / /| |')
189 log.info('| |/ / /_/ / /___/ / / __ / ___ |')
190 log.info('|___/\____/_____/_/ /_/ /_/_/ |_|')
Zsolt Haraszti59b7a882016-09-12 14:42:59 -0700191 log.info('(to stop: press Ctrl-C)')
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700192
193
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700194class Main(object):
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700195
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700196 def __init__(self):
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700197
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700198 self.args = args = parse_args()
199 self.config = load_config(args)
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700200
201 verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
Zsolt Haraszti109db832016-09-16 16:32:36 -0700202 self.log = setup_logging(self.config.get('logging', {}),
203 args.instance_id,
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700204 verbosity_adjust=verbosity_adjust,
Zsolt Haraszti109db832016-09-16 16:32:36 -0700205 fluentd=args.fluentd)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700206
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700207 # components
208 self.coordinator = None
Zsolt Harasztieb435072016-09-23 17:10:49 -0700209 self.grpc_server = None
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700210
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700211 if not args.no_banner:
212 print_banner(self.log)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700213
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700214 if not args.no_heartbeat:
215 self.start_heartbeat()
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700216
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700217 self.startup_components()
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700218
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700219 def start(self):
220 self.start_reactor() # will not return except Keyboard interrupt
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700221
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700222 def startup_components(self):
223 self.log.info('starting-internal-components')
224 self.coordinator = Coordinator(
225 internal_host_address=self.args.internal_host_address,
226 external_host_address=self.args.external_host_address,
227 rest_port=self.args.rest_port,
228 instance_id=self.args.instance_id,
229 consul=self.args.consul)
230 init_rest_service(self.args.rest_port)
Zsolt Harasztieb435072016-09-23 17:10:49 -0700231
Zsolt Haraszti553826c2016-09-27 10:24:27 -0700232 self.grpc_server = VolthaGrpcServer(self.args.grpc_port).run()
Zsolt Harasztieb435072016-09-23 17:10:49 -0700233
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700234 self.log.info('started-internal-services')
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700235
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700236 @inlineCallbacks
237 def shutdown_components(self):
238 """Execute before the reactor is shut down"""
239 self.log.info('exiting-on-keyboard-interrupt')
Zsolt Harasztieb435072016-09-23 17:10:49 -0700240 if self.coordinator is not None:
241 yield self.coordinator.shutdown()
242 if self.grpc_server is not None:
243 yield self.grpc_server.shutdown()
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700244
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700245 def start_reactor(self):
246 from twisted.internet import reactor
Zsolt Haraszti109db832016-09-16 16:32:36 -0700247 reactor.callWhenRunning(
248 lambda: self.log.info('twisted-reactor-started'))
249 reactor.addSystemEventTrigger('before', 'shutdown',
250 self.shutdown_components)
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700251 reactor.run()
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700252
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700253 def start_heartbeat(self):
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700254
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700255 t0 = time.time()
256 t0s = time.ctime(t0)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700257
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700258 def heartbeat():
259 self.log.debug(status='up', since=t0s, uptime=time.time() - t0)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700260
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700261 from twisted.internet.task import LoopingCall
262 lc = LoopingCall(heartbeat)
263 lc.start(10)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700264
265
266if __name__ == '__main__':
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700267 Main().start()