blob: 144a0ade1c37f7e78302e27d8f3ffb5ff6468c12 [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'),
Zack Williams55b456e2018-11-03 20:08:53 -070031 logconfig=os.environ.get('LOGCONFIG', './logconfig.yml'),
Khen Nursimulu68b9be32016-10-25 11:57:04 -040032 consul=os.environ.get('CONSUL', 'localhost:8500'),
Zsolt Harasztiee5c4c82017-01-09 14:37:57 -080033 controller=os.environ.get('CONTROLLER', 'localhost:6653'),
Khen Nursimulu68b9be32016-10-25 11:57:04 -040034 external_host_address=os.environ.get('EXTERNAL_HOST_ADDRESS',
35 get_my_primary_local_ipv4()),
36 grpc_endpoint=os.environ.get('GRPC_ENDPOINT', 'localhost:50055'),
Khen Nursimulu68b9be32016-10-25 11:57:04 -040037 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
Zack Williams55b456e2018-11-03 20:08:53 -070059 _help = ('Path to logconfig.yml config file (default: %s). '
60 'If relative, it is relative to main.py of voltha.'
61 % defs['logconfig'])
62 parser.add_argument('-l', '--logconfig',
63 dest='logconfig',
64 action='store',
65 default=defs['logconfig'],
66 help=_help)
67
Khen Nursimulu68b9be32016-10-25 11:57:04 -040068 _help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
69 parser.add_argument(
70 '-C', '--consul', dest='consul', action='store',
71 default=defs['consul'],
72 help=_help)
73
sgovindacc736782017-05-02 20:06:37 +053074 _help = '<hostname1>:<port1> <hostname2>:<port2> <hostname3>:<port3> ... <hostnamen>:<portn> to openflow controller (default: %s)' % \
Khen Nursimulu68b9be32016-10-25 11:57:04 -040075 defs['controller']
76 parser.add_argument(
sgovindacc736782017-05-02 20:06:37 +053077 '-O', '--controller',nargs = '*', dest='controller', action='store',
Khen Nursimulu68b9be32016-10-25 11:57:04 -040078 default=defs['controller'],
79 help=_help)
80
81 _help = ('<hostname> or <ip> at which ofagent is reachable from outside '
82 'the cluster (default: %s)' % defs['external_host_address'])
83 parser.add_argument('-E', '--external-host-address',
84 dest='external_host_address',
85 action='store',
86 default=defs['external_host_address'],
87 help=_help)
88
Khen Nursimulu68b9be32016-10-25 11:57:04 -040089 _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
Zack Williams55b456e2018-11-03 20:08:53 -0700185def load_config(args, configname='config'):
186 argdict = vars(args)
187 path = argdict[configname]
Zsolt Haraszti8a774382016-10-24 18:25:54 -0700188 if path.startswith('.'):
189 dir = os.path.dirname(os.path.abspath(__file__))
190 path = os.path.join(dir, path)
191 path = os.path.abspath(path)
192 with open(path) as fd:
193 config = yaml.load(fd)
194 return config
195
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400196banner = r'''
197 ___ _____ _ _
198 / _ \| ___/ \ __ _ ___ _ __ | |_
199| | | | |_ / _ \ / _` |/ _ \ '_ \| __|
200| |_| | _/ ___ \ (_| | __/ | | | |_
201 \___/|_|/_/ \_\__, |\___|_| |_|\__|
202 |___/
203'''
204
205def print_banner(log):
206 for line in banner.strip('\n').splitlines():
207 log.info(line)
208 log.info('(to stop: press Ctrl-C)')
209
210
211class Main(object):
212
213 def __init__(self):
214
215 self.args = args = parse_args()
216 self.config = load_config(args)
Zack Williams55b456e2018-11-03 20:08:53 -0700217 self.logconfig = load_config(args, 'logconfig')
218
Richard Jankowskidb9a86e2018-09-17 13:33:29 -0400219 # May want to specify the gRPC timeout as an arg (in future)
220 # Right now, set a default value
221 self.grpc_timeout = 10
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400222
223 verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
Zack Williams55b456e2018-11-03 20:08:53 -0700224 self.log = setup_logging(self.logconfig,
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400225 args.instance_id,
khenaidoo50b286d2018-03-02 17:44:30 -0500226 verbosity_adjust=verbosity_adjust)
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400227
228 # components
229 self.connection_manager = None
230
231 self.exiting = False
232
233 if not args.no_banner:
234 print_banner(self.log)
235
236 self.startup_components()
237
238 def start(self):
239 self.start_reactor() # will not return except Keyboard interrupt
240
241 @inlineCallbacks
242 def startup_components(self):
243 self.log.info('starting-internal-components')
244 args = self.args
Zsolt Haraszticd22adc2016-10-25 00:13:06 -0700245 self.connection_manager = yield ConnectionManager(
Richard Jankowskidb9a86e2018-09-17 13:33:29 -0400246 args.consul, args.grpc_endpoint, self.grpc_timeout,
247 args.controller, args.instance_id,
Girishf6eeaea2017-11-13 10:53:57 +0530248 args.enable_tls, args.key_file, args.cert_file).start()
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400249 self.log.info('started-internal-services')
250
251 @inlineCallbacks
252 def shutdown_components(self):
253 """Execute before the reactor is shut down"""
254 self.log.info('exiting-on-keyboard-interrupt')
255 self.exiting = True
256 if self.connection_manager is not None:
Zsolt Haraszti2bdb6b32016-11-03 16:56:17 -0700257 yield self.connection_manager.stop()
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400258
259 def start_reactor(self):
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400260 reactor.callWhenRunning(
261 lambda: self.log.info('twisted-reactor-started'))
262
263 reactor.addSystemEventTrigger('before', 'shutdown',
264 self.shutdown_components)
265 reactor.run()
266
Zsolt Haraszti8a774382016-10-24 18:25:54 -0700267
Zsolt Haraszti023ea7c2016-10-16 19:30:34 -0700268if __name__ == '__main__':
Khen Nursimulu68b9be32016-10-25 11:57:04 -0400269 Main().start()