blob: 5887b75246e03c3373d11b7f3813d1b2fe13d3f6 [file] [log] [blame]
Zsolt Haraszti023ea7c2016-10-16 19:30:34 -07001#!/usr/bin/env python
2#
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08003# Copyright 2017 the original author or authors.
Zsolt Haraszti023ea7c2016-10-16 19:30:34 -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#
Khen Nursimulu68b9be32016-10-25 11:57:04 -040017import argparse
Zsolt Haraszti8a774382016-10-24 18:25:54 -070018import os
Zsolt Harasztid70cd4d2016-11-03 23:23:36 -070019
Zsolt Haraszti8a774382016-10-24 18:25:54 -070020import yaml
Zsolt Haraszti2bdb6b32016-11-03 16:56:17 -070021from twisted.internet import reactor
Khen Nursimulu68b9be32016-10-25 11:57:04 -040022from twisted.internet.defer import inlineCallbacks
Zsolt Haraszti023ea7c2016-10-16 19:30:34 -070023
Zsolt Harasztid70cd4d2016-11-03 23:23:36 -070024from common.structlog_setup import setup_logging
Khen Nursimulu68b9be32016-10-25 11:57:04 -040025from common.utils.dockerhelpers import get_my_containers_name
26from common.utils.nethelpers import get_my_primary_local_ipv4
Khen Nursimulu68b9be32016-10-25 11:57:04 -040027from connection_mgr import ConnectionManager
Zsolt Haraszti023ea7c2016-10-16 19:30:34 -070028
Khen Nursimulu68b9be32016-10-25 11:57:04 -040029defs = dict(
30 config=os.environ.get('CONFIG', './ofagent.yml'),
31 consul=os.environ.get('CONSUL', 'localhost:8500'),
Zsolt Harasztiee5c4c82017-01-09 14:37:57 -080032 controller=os.environ.get('CONTROLLER', 'localhost:6653'),
Khen Nursimulu68b9be32016-10-25 11:57:04 -040033 external_host_address=os.environ.get('EXTERNAL_HOST_ADDRESS',
34 get_my_primary_local_ipv4()),
35 grpc_endpoint=os.environ.get('GRPC_ENDPOINT', 'localhost:50055'),
36 fluentd=os.environ.get('FLUENTD', None),
37 instance_id=os.environ.get('INSTANCE_ID', os.environ.get('HOSTNAME', '1')),
38 internal_host_address=os.environ.get('INTERNAL_HOST_ADDRESS',
39 get_my_primary_local_ipv4()),
Girishf6eeaea2017-11-13 10:53:57 +053040 work_dir=os.environ.get('WORK_DIR', '/tmp/ofagent'),
41 key_file=os.environ.get('KEY_FILE', '/ofagent/pki/voltha.key'),
42 cert_file=os.environ.get('CERT_FILE', '/ofagent/pki/voltha.crt')
Khen Nursimulu68b9be32016-10-25 11:57:04 -040043)
Zsolt Haraszti023ea7c2016-10-16 19:30:34 -070044
45
Khen Nursimulu68b9be32016-10-25 11:57:04 -040046def parse_args():
47
48 parser = argparse.ArgumentParser()
49
50 _help = ('Path to ofagent.yml config file (default: %s). '
51 'If relative, it is relative to main.py of ofagent.'
52 % defs['config'])
53 parser.add_argument('-c', '--config',
54 dest='config',
55 action='store',
56 default=defs['config'],
57 help=_help)
58
59 _help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
60 parser.add_argument(
61 '-C', '--consul', dest='consul', action='store',
62 default=defs['consul'],
63 help=_help)
64
sgovindacc736782017-05-02 20:06:37 +053065 _help = '<hostname1>:<port1> <hostname2>:<port2> <hostname3>:<port3> ... <hostnamen>:<portn> to openflow controller (default: %s)' % \
Khen Nursimulu68b9be32016-10-25 11:57:04 -040066 defs['controller']
67 parser.add_argument(
sgovindacc736782017-05-02 20:06:37 +053068 '-O', '--controller',nargs = '*', dest='controller', action='store',
Khen Nursimulu68b9be32016-10-25 11:57:04 -040069 default=defs['controller'],
70 help=_help)
71
72 _help = ('<hostname> or <ip> at which ofagent 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',
77 default=defs['external_host_address'],
78 help=_help)
79
80 _help = ('<hostname>:<port> to fluentd server (default: %s). (If not '
81 'specified (None), the address from the config file is used'
82 % defs['fluentd'])
83 parser.add_argument('-F', '--fluentd',
84 dest='fluentd',
85 action='store',
86 default=defs['fluentd'],
87 help=_help)
88
89 _help = ('gRPC end-point to connect to. It can either be a direct'
90 'definition in the form of <hostname>:<port>, or it can be an'
91 'indirect definition in the form of @<service-name> where'
92 '<service-name> is the name of the grpc service as registered'
93 'in consul (example: @voltha-grpc). (default: %s'
94 % defs['grpc_endpoint'])
95 parser.add_argument('-G', '--grpc-endpoint',
96 dest='grpc_endpoint',
97 action='store',
98 default=defs['grpc_endpoint'],
99 help=_help)
100
101 _help = ('<hostname> or <ip> at which ofagent is reachable from inside'
102 'the cluster (default: %s)' % defs['internal_host_address'])
103 parser.add_argument('-H', '--internal-host-address',
104 dest='internal_host_address',
105 action='store',
106 default=defs['internal_host_address'],
107 help=_help)
108
109 _help = ('unique string id of this ofagent instance (default: %s)'
110 % defs['instance_id'])
111 parser.add_argument('-i', '--instance-id',
112 dest='instance_id',
113 action='store',
114 default=defs['instance_id'],
115 help=_help)
116
117 _help = 'omit startup banner log lines'
118 parser.add_argument('-n', '--no-banner',
119 dest='no_banner',
120 action='store_true',
121 default=False,
122 help=_help)
123
124 _help = "suppress debug and info logs"
125 parser.add_argument('-q', '--quiet',
126 dest='quiet',
127 action='count',
128 help=_help)
129
130 _help = 'enable verbose logging'
131 parser.add_argument('-v', '--verbose',
132 dest='verbose',
133 action='count',
134 help=_help)
135
136 _help = ('work dir to compile and assemble generated files (default=%s)'
137 % defs['work_dir'])
138 parser.add_argument('-w', '--work-dir',
139 dest='work_dir',
140 action='store',
141 default=defs['work_dir'],
142 help=_help)
143
144 _help = ('use docker container name as ofagent instance id'
145 ' (overrides -i/--instance-id option)')
146 parser.add_argument('--instance-id-is-container-name',
147 dest='instance_id_is_container_name',
148 action='store_true',
149 default=False,
150 help=_help)
151
Girishf6eeaea2017-11-13 10:53:57 +0530152 _help = ('Specify this option to enable TLS security between ofagent \
153 and onos.')
154 parser.add_argument('-t', '--enable-tls',
155 dest='enable_tls',
156 action='store_true',
157 help=_help)
158
159 _help = ('key file to be used for tls security (default=%s)'
160 % defs['key_file'])
161 parser.add_argument('-k', '--key-file',
162 dest='key_file',
163 action='store',
164 default=defs['key_file'],
165 help=_help)
166
167 _help = ('certificate file to be used for tls security (default=%s)'
168 % defs['cert_file'])
169 parser.add_argument('-r', '--cert-file',
170 dest='cert_file',
171 action='store',
172 default=defs['cert_file'],
173 help=_help)
174
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400175 args = parser.parse_args()
176
177 # post-processing
178
179 if args.instance_id_is_container_name:
180 args.instance_id = get_my_containers_name()
181
182 return args
183
184
185def load_config(args):
186 path = args.config
Zsolt Haraszti8a774382016-10-24 18:25:54 -0700187 if path.startswith('.'):
188 dir = os.path.dirname(os.path.abspath(__file__))
189 path = os.path.join(dir, path)
190 path = os.path.abspath(path)
191 with open(path) as fd:
192 config = yaml.load(fd)
193 return config
194
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400195banner = r'''
196 ___ _____ _ _
197 / _ \| ___/ \ __ _ ___ _ __ | |_
198| | | | |_ / _ \ / _` |/ _ \ '_ \| __|
199| |_| | _/ ___ \ (_| | __/ | | | |_
200 \___/|_|/_/ \_\__, |\___|_| |_|\__|
201 |___/
202'''
203
204def print_banner(log):
205 for line in banner.strip('\n').splitlines():
206 log.info(line)
207 log.info('(to stop: press Ctrl-C)')
208
209
210class Main(object):
211
212 def __init__(self):
213
214 self.args = args = parse_args()
215 self.config = load_config(args)
216
217 verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
218 self.log = setup_logging(self.config.get('logging', {}),
219 args.instance_id,
220 verbosity_adjust=verbosity_adjust,
221 fluentd=args.fluentd)
222
223 # components
224 self.connection_manager = None
225
226 self.exiting = False
227
228 if not args.no_banner:
229 print_banner(self.log)
230
231 self.startup_components()
232
233 def start(self):
234 self.start_reactor() # will not return except Keyboard interrupt
235
236 @inlineCallbacks
237 def startup_components(self):
238 self.log.info('starting-internal-components')
239 args = self.args
Zsolt Haraszticd22adc2016-10-25 00:13:06 -0700240 self.connection_manager = yield ConnectionManager(
Richard Jankowskic9d89202018-01-25 10:25:10 -0500241 args.consul, args.grpc_endpoint, args.controller, args.instance_id, \
Girishf6eeaea2017-11-13 10:53:57 +0530242 args.enable_tls, args.key_file, args.cert_file).start()
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400243 self.log.info('started-internal-services')
244
245 @inlineCallbacks
246 def shutdown_components(self):
247 """Execute before the reactor is shut down"""
248 self.log.info('exiting-on-keyboard-interrupt')
249 self.exiting = True
250 if self.connection_manager is not None:
Zsolt Haraszti2bdb6b32016-11-03 16:56:17 -0700251 yield self.connection_manager.stop()
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400252
253 def start_reactor(self):
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400254 reactor.callWhenRunning(
255 lambda: self.log.info('twisted-reactor-started'))
256
257 reactor.addSystemEventTrigger('before', 'shutdown',
258 self.shutdown_components)
259 reactor.run()
260
Zsolt Haraszti8a774382016-10-24 18:25:54 -0700261
Zsolt Haraszti023ea7c2016-10-16 19:30:34 -0700262if __name__ == '__main__':
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400263 Main().start()