blob: 160eb76d01227343bed9b2b1c025af7914cf375f [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 Harasztif2da1d02016-09-13 23:21:35 -070022import time
Zsolt Harasztieb435072016-09-23 17:10:49 -070023
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 Harasztieb435072016-09-23 17:10:49 -070027from voltha.coordinator import Coordinator
28from voltha.dockerhelpers import get_my_containers_name
29from voltha.nethelpers import get_my_primary_interface, get_my_primary_local_ipv4
30from voltha.northbound.grpc.grpc_server import VolthaGrpcServer
31from voltha.northbound.rest.health_check import init_rest_service
32from voltha.structlog_setup import setup_logging
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070033
34defs = dict(
35 consul=os.environ.get('CONSUL', 'localhost:8500'),
Zsolt Haraszti28e0f1c2016-09-13 23:55:43 -070036 instance_id=os.environ.get('INSTANCE_ID', os.environ.get('HOSTNAME', '1')),
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070037 config=os.environ.get('CONFIG', './voltha.yml'),
Zsolt Harasztide22bbc2016-09-14 15:27:33 -070038 interface=os.environ.get('INTERFACE', get_my_primary_interface()),
Zsolt Haraszti109db832016-09-16 16:32:36 -070039 internal_host_address=os.environ.get('INTERNAL_HOST_ADDRESS',
40 get_my_primary_local_ipv4()),
41 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),
44 rest_port=os.environ.get('REST_PORT', 8880),
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070045)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -070046
47
48def parse_args():
49
50 parser = argparse.ArgumentParser()
51
Zsolt Haraszti109db832016-09-16 16:32:36 -070052 _help = ('Path to voltha.yml config file (default: %s). '
53 'If relative, it is relative to main.py of voltha.'
54 % defs['config'])
55 parser.add_argument('-c', '--config',
56 dest='config',
57 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070058 default=defs['config'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070059 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070060
Zsolt Haraszti109db832016-09-16 16:32:36 -070061 _help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
62 parser.add_argument(
63 '-C', '--consul', dest='consul', action='store',
64 default=defs['consul'],
65 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070066
Zsolt Haraszti109db832016-09-16 16:32:36 -070067 _help = ('<hostname> or <ip> at which Voltha is reachable from outside '
68 'the cluster (default: %s)' % defs['external_host_address'])
69 parser.add_argument('-E', '--external-host-address',
70 dest='external_host_address',
71 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070072 default=defs['external_host_address'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070073 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070074
Zsolt Haraszti109db832016-09-16 16:32:36 -070075 _help = ('<hostname>:<port> to fluentd server (default: %s). (If not '
76 'specified (None), the address from the config file is used'
77 % defs['fluentd'])
78 parser.add_argument('-F', '--fluentd',
79 dest='fluentd',
80 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070081 default=defs['fluentd'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070082 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070083
Zsolt Haraszti109db832016-09-16 16:32:36 -070084 _help = ('<hostname> or <ip> at which Voltha is reachable from inside the'
85 'cluster (default: %s)' % defs['internal_host_address'])
86 parser.add_argument('-H', '--internal-host-address',
87 dest='internal_host_address',
88 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070089 default=defs['internal_host_address'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070090 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070091
Zsolt Haraszti109db832016-09-16 16:32:36 -070092 _help = ('unique string id of this voltha instance (default: %s)'
93 % defs['interface'])
94 parser.add_argument('-i', '--instance-id',
95 dest='instance_id',
96 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070097 default=defs['instance_id'],
Zsolt Haraszti109db832016-09-16 16:32:36 -070098 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -070099
100 # TODO placeholder, not used yet
Zsolt Haraszti109db832016-09-16 16:32:36 -0700101 _help = 'ETH interface to send (default: %s)' % defs['interface']
102 parser.add_argument('-I', '--interface',
103 dest='interface',
104 action='store',
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700105 default=defs['interface'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700106 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700107
Zsolt Haraszti109db832016-09-16 16:32:36 -0700108 _help = 'omit startup banner log lines'
109 parser.add_argument('-n', '--no-banner',
110 dest='no_banner',
111 action='store_true',
112 default=False,
113 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700114
Zsolt Haraszti109db832016-09-16 16:32:36 -0700115 _help = 'do not emit periodic heartbeat log messages'
116 parser.add_argument('-N', '--no-heartbeat',
117 dest='no_heartbeat',
118 action='store_true',
119 default=False,
120 help=_help)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700121
Zsolt Haraszti109db832016-09-16 16:32:36 -0700122 _help = ('port number for the rest service (default: %d)'
123 % defs['rest_port'])
124 parser.add_argument('-R', '--rest-port',
125 dest='rest_port',
126 action='store',
127 type=int,
Zsolt Harasztide22bbc2016-09-14 15:27:33 -0700128 default=defs['rest_port'],
Zsolt Haraszti109db832016-09-16 16:32:36 -0700129 help=_help)
Zsolt Harasztide22bbc2016-09-14 15:27:33 -0700130
Zsolt Haraszti109db832016-09-16 16:32:36 -0700131 _help = "suppress debug and info logs"
132 parser.add_argument('-q', '--quiet',
133 dest='quiet',
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700134 action='count',
Zsolt Haraszti109db832016-09-16 16:32:36 -0700135 help=_help)
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -0700136
Zsolt Haraszti109db832016-09-16 16:32:36 -0700137 _help = 'enable verbose logging'
138 parser.add_argument('-v', '--verbose',
139 dest='verbose',
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700140 action='count',
Zsolt Haraszti109db832016-09-16 16:32:36 -0700141 help=_help)
Zsolt Harasztiadbb88d2016-09-12 21:24:57 -0700142
Zsolt Haraszti109db832016-09-16 16:32:36 -0700143 _help = ('use docker container name as voltha instance id'
144 ' (overrides -i/--instance-id option)')
145 parser.add_argument('--instance-id-is-container-name',
146 dest='instance_id_is_container_name',
147 action='store_true',
148 default=False,
149 help=_help)
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700150
151 args = parser.parse_args()
152
153 # post-processing
154
155 if args.instance_id_is_container_name:
156 args.instance_id = get_my_containers_name()
157
158 return args
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700159
160
Zsolt Harasztid7c7c482016-09-13 00:45:38 -0700161def load_config(args):
162 path = args.config
163 if path.startswith('.'):
164 dir = os.path.dirname(os.path.abspath(__file__))
165 path = os.path.join(dir, path)
166 path = os.path.abspath(path)
167 with open(path) as fd:
168 config = yaml.load(fd)
169 return config
170
171
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700172def print_banner(log):
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700173 log.info(' _ ______ __ ________ _____ ')
174 log.info('| | / / __ \/ / /_ __/ / / / |')
175 log.info('| | / / / / / / / / / /_/ / /| |')
176 log.info('| |/ / /_/ / /___/ / / __ / ___ |')
177 log.info('|___/\____/_____/_/ /_/ /_/_/ |_|')
Zsolt Haraszti59b7a882016-09-12 14:42:59 -0700178 log.info('(to stop: press Ctrl-C)')
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700179
180
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700181class Main(object):
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700182
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700183 def __init__(self):
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700184
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700185 self.args = args = parse_args()
186 self.config = load_config(args)
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700187
188 verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
Zsolt Haraszti109db832016-09-16 16:32:36 -0700189 self.log = setup_logging(self.config.get('logging', {}),
190 args.instance_id,
Zsolt Haraszti1420def2016-09-18 00:07:31 -0700191 verbosity_adjust=verbosity_adjust,
Zsolt Haraszti109db832016-09-16 16:32:36 -0700192 fluentd=args.fluentd)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700193
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700194 # components
195 self.coordinator = None
Zsolt Harasztieb435072016-09-23 17:10:49 -0700196 self.grpc_server = None
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700197
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700198 if not args.no_banner:
199 print_banner(self.log)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700200
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700201 if not args.no_heartbeat:
202 self.start_heartbeat()
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700203
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700204 self.startup_components()
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700205
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700206 def start(self):
207 self.start_reactor() # will not return except Keyboard interrupt
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700208
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700209 def startup_components(self):
210 self.log.info('starting-internal-components')
211 self.coordinator = Coordinator(
212 internal_host_address=self.args.internal_host_address,
213 external_host_address=self.args.external_host_address,
214 rest_port=self.args.rest_port,
215 instance_id=self.args.instance_id,
216 consul=self.args.consul)
217 init_rest_service(self.args.rest_port)
Zsolt Harasztieb435072016-09-23 17:10:49 -0700218
219 self.grpc_server = VolthaGrpcServer().run()
220
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700221 self.log.info('started-internal-services')
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700222
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700223 @inlineCallbacks
224 def shutdown_components(self):
225 """Execute before the reactor is shut down"""
226 self.log.info('exiting-on-keyboard-interrupt')
Zsolt Harasztieb435072016-09-23 17:10:49 -0700227 if self.coordinator is not None:
228 yield self.coordinator.shutdown()
229 if self.grpc_server is not None:
230 yield self.grpc_server.shutdown()
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700231
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700232 def start_reactor(self):
233 from twisted.internet import reactor
Zsolt Haraszti109db832016-09-16 16:32:36 -0700234 reactor.callWhenRunning(
235 lambda: self.log.info('twisted-reactor-started'))
236 reactor.addSystemEventTrigger('before', 'shutdown',
237 self.shutdown_components)
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700238 reactor.run()
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700239
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700240 def start_heartbeat(self):
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700241
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700242 t0 = time.time()
243 t0s = time.ctime(t0)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700244
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700245 def heartbeat():
246 self.log.debug(status='up', since=t0s, uptime=time.time() - t0)
Zsolt Harasztif2da1d02016-09-13 23:21:35 -0700247
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700248 from twisted.internet.task import LoopingCall
249 lc = LoopingCall(heartbeat)
250 lc.start(10)
Zsolt Harasztib71c2a02016-09-12 13:12:07 -0700251
252
253if __name__ == '__main__':
Zsolt Harasztie060a7d2016-09-16 11:08:24 -0700254 Main().start()