blob: cd515e624d33ed7cbde71efd8dc4d35ff8e5ffce [file] [log] [blame]
alshabibc67ee3a2016-10-25 23:24:03 -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
18import argparse
19import os
20from consul_mgr import ConsulManager
21from twisted.internet.defer import inlineCallbacks
22from common.utils.nethelpers import get_my_primary_local_ipv4
23from common.utils.structlog_setup import setup_logging
24import yaml
25
26defs = dict(
27 config=os.environ.get('CONFIG', './podder.yml'),
28 consul=os.environ.get('CONSUL', 'localhost:8500'),
29 external_host_address=os.environ.get('EXTERNAL_HOST_ADDRESS',
30 get_my_primary_local_ipv4()),
31 grpc_endpoint=os.environ.get('GRPC_ENDPOINT', 'localhost:50055'),
32 fluentd=os.environ.get('FLUENTD', None),
33 instance_id=os.environ.get('INSTANCE_ID', os.environ.get('HOSTNAME', '1')),
34 internal_host_address=os.environ.get('INTERNAL_HOST_ADDRESS',
35 get_my_primary_local_ipv4()),
36 work_dir=os.environ.get('WORK_DIR', '/tmp/podder')
37)
38
39def parse_args():
40
41 parser = argparse.ArgumentParser()
42
43 _help = ('Path to podder.yml config file (default: %s). '
44 'If relative, it is relative to main.py of podder.'
45 % defs['config'])
46 parser.add_argument('-c', '--config',
47 dest='config',
48 action='store',
49 default=defs['config'],
50 help=_help)
51
52 _help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
53 parser.add_argument(
54 '-C', '--consul', dest='consul', action='store',
55 default=defs['consul'],
56 help=_help)
57
58
59 _help = ('<hostname>:<port> to fluentd server (default: %s). (If not '
60 'specified (None), the address from the config file is used'
61 % defs['fluentd'])
62 parser.add_argument('-F', '--fluentd',
63 dest='fluentd',
64 action='store',
65 default=defs['fluentd'],
66 help=_help)
67
68 _help = ('unique string id of this ofagent instance (default: %s)'
69 % defs['instance_id'])
70 parser.add_argument('-i', '--instance-id',
71 dest='instance_id',
72 action='store',
73 default=defs['instance_id'],
74 help=_help)
75
76 _help = 'omit startup banner log lines'
77 parser.add_argument('-n', '--no-banner',
78 dest='no_banner',
79 action='store_true',
80 default=False,
81 help=_help)
82
83 _help = "suppress debug and info logs"
84 parser.add_argument('-q', '--quiet',
85 dest='quiet',
86 action='count',
87 help=_help)
88
89 _help = 'enable verbose logging'
90 parser.add_argument('-v', '--verbose',
91 dest='verbose',
92 action='count',
93 help=_help)
94
95
96 args = parser.parse_args()
97
98 # post-processing
99
100 return args
101
102def load_config(args):
103 path = args.config
104 if path.startswith('.'):
105 dir = os.path.dirname(os.path.abspath(__file__))
106 path = os.path.join(dir, path)
107 path = os.path.abspath(path)
108 with open(path) as fd:
109 config = yaml.load(fd)
110 return config
111
112banner = r'''
113 _____
114| | | |
115| | | |
116|_____|_____ ____|____| ___ _
117| | | | |/ _ \ /
118| |_____|____|____|\____|
119'''
120
121def print_banner(log):
122 for line in banner.strip('\n').splitlines():
123 log.info(line)
124 log.info('(to stop: press Ctrl-C)')
125
126class Main(object):
127
128 def __init__(self):
129 self.args = args = parse_args()
130 self.config = load_config(args)
131
132 verbosity_adjust = (args.verbose or 0) - (args.quiet or 0)
133 self.log = setup_logging(self.config.get('logging', {}),
134 args.instance_id,
135 verbosity_adjust=verbosity_adjust,
136 fluentd=args.fluentd)
137
138 self.consul_manager = None
139
140 if not args.no_banner:
141 print_banner(self.log)
142
143 self.startup_components()
144
145 def start(self):
146 self.start_reactor()
147
148 @inlineCallbacks
149 def startup_components(self):
150 self.log.info('starting-internal-components')
151 args = self.args
152 self.consul_manager = yield ConsulManager(args.consul).run()
153 self.log.info('started-internal-components')
154
155 @inlineCallbacks
156 def shutdown_components(self):
157 """Execute before the reactor is shut down"""
158 self.log.info('exiting-on-keyboard-interrupt')
159 if self.consul_manager is not None:
160 yield self.consul_manager.shutdown()
161
162 def start_reactor(self):
163 from twisted.internet import reactor
164 reactor.callWhenRunning(
165 lambda: self.log.info('twisted-reactor-started'))
166
167 reactor.addSystemEventTrigger('before', 'shutdown',
168 self.shutdown_components)
169 reactor.run()
170
171
172if __name__ == '__main__':
173 Main().start()