Skip to content

Commit 0c311d7

Browse files
committed
Move common API code into shared library
1 parent 8cfed85 commit 0c311d7

File tree

13 files changed

+451
-562
lines changed

13 files changed

+451
-562
lines changed

st2api/st2api/app.py

+23-67
Original file line numberDiff line numberDiff line change
@@ -16,83 +16,39 @@
1616
from oslo_config import cfg
1717

1818
from st2api import config as st2api_config
19-
from st2common import log as logging
20-
from st2common.middleware.streaming import StreamingMiddleware
21-
from st2common.middleware.error_handling import ErrorHandlingMiddleware
22-
from st2common.middleware.cors import CorsMiddleware
23-
from st2common.middleware.request_id import RequestIDMiddleware
24-
from st2common.middleware.logging import LoggingMiddleware
25-
from st2common.middleware.instrumentation import RequestInstrumentationMiddleware
26-
from st2common.middleware.instrumentation import ResponseInstrumentationMiddleware
27-
from st2common.router import Router
28-
from st2common.constants.system import VERSION_STRING
29-
from st2common.service_setup import setup as common_setup
30-
from st2common.util import spec_loader
19+
from st2common.openapi import app
3120
from st2api.validation import validate_auth_cookie_is_correctly_configured
3221
from st2api.validation import validate_rbac_is_correctly_configured
3322

34-
LOG = logging.getLogger(__name__)
3523

24+
def setup_app(config={}):
25+
common_setup = {
26+
"register_mq_exchanges": True,
27+
"register_internal_trigger_types": True,
28+
"run_migrations": True,
29+
}
3630

37-
def setup_app(config=None):
38-
config = config or {}
39-
40-
LOG.info("Creating st2api: %s as OpenAPI app.", VERSION_STRING)
41-
42-
is_gunicorn = config.get("is_gunicorn", False)
43-
if is_gunicorn:
44-
# NOTE: We only want to perform this logic in the WSGI worker
45-
st2api_config.register_opts(ignore_errors=True)
46-
capabilities = {
47-
"name": "api",
48-
"listen_host": cfg.CONF.api.host,
49-
"listen_port": cfg.CONF.api.port,
50-
"listen_ssl": cfg.CONF.api.use_ssl,
51-
"type": "active",
52-
}
53-
54-
# This should be called in gunicorn case because we only want
55-
# workers to connect to db, rabbbitmq etc. In standalone HTTP
56-
# server case, this setup would have already occurred.
57-
common_setup(
58-
service="api",
59-
config=st2api_config,
60-
setup_db=True,
61-
register_mq_exchanges=True,
62-
register_signal_handlers=True,
63-
register_internal_trigger_types=True,
64-
run_migrations=True,
65-
service_registry=True,
66-
capabilities=capabilities,
67-
config_args=config.get("config_args", None),
68-
)
69-
70-
# Additional pre-run time checks
71-
validate_auth_cookie_is_correctly_configured()
72-
validate_rbac_is_correctly_configured()
73-
74-
router = Router(
75-
debug=cfg.CONF.api.debug, auth=cfg.CONF.auth.enable, is_gunicorn=is_gunicorn
76-
)
31+
pre_run_checks = [
32+
validate_auth_cookie_is_correctly_configured,
33+
validate_rbac_is_correctly_configured,
34+
]
7735

78-
spec = spec_loader.load_spec("st2common", "openapi.yaml.j2")
7936
transforms = {
8037
"^/api/v1/$": ["/v1"],
8138
"^/api/v1/": ["/", "/v1/"],
8239
"^/api/v1/executions": ["/actionexecutions", "/v1/actionexecutions"],
8340
"^/api/exp/": ["/exp/"],
8441
}
85-
router.add_spec(spec, transforms=transforms)
86-
87-
app = router.as_wsgi
8842

89-
# Order is important. Check middleware for detailed explanation.
90-
app = StreamingMiddleware(app, path_whitelist=["/v1/executions/*/output*"])
91-
app = ErrorHandlingMiddleware(app)
92-
app = CorsMiddleware(app)
93-
app = LoggingMiddleware(app, router)
94-
app = ResponseInstrumentationMiddleware(app, router, service_name="api")
95-
app = RequestIDMiddleware(app)
96-
app = RequestInstrumentationMiddleware(app, router, service_name="api")
97-
98-
return app
43+
path_whitelist = ["/v1/executions/*/output*"]
44+
45+
return app.setup_app(
46+
service_name="api",
47+
app_config=st2api_config,
48+
oslo_cfg=cfg.CONF.api,
49+
pre_run_checks=pre_run_checks,
50+
transforms=transforms,
51+
common_setup_kwargs=common_setup,
52+
path_whitelist=path_whitelist,
53+
config=config,
54+
)

st2api/st2api/cmd/api.py

+20-87
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16-
import os
17-
import sys
18-
1916
# NOTE: It's important that we perform monkey patch as early as possible before any other modules
2017
# are important, otherwise SSL support for MongoDB won't work.
2118
# See https://github.com/StackStorm/st2/issues/4832 and https://github.com/gevent/gevent/issues/1016
@@ -24,15 +21,11 @@
2421

2522
monkey_patch()
2623

27-
import eventlet
2824
from oslo_config import cfg
29-
from eventlet import wsgi
3025

3126
from st2common import log as logging
32-
from st2common.service_setup import setup as common_setup
33-
from st2common.service_setup import teardown as common_teardown
34-
from st2common.service_setup import deregister_service
3527
from st2api import config
28+
from st2common.openapi import api
3629

3730
config.register_opts(ignore_errors=True)
3831

@@ -43,87 +36,27 @@
4336
__all__ = ["main"]
4437

4538
LOG = logging.getLogger(__name__)
46-
API = "api"
47-
48-
# How much time to give to the request in progress to finish in seconds before killing them
49-
WSGI_SERVER_REQUEST_SHUTDOWN_TIME = 2
5039

5140

52-
def _setup():
53-
capabilities = {
54-
"name": "api",
55-
"listen_host": cfg.CONF.api.host,
56-
"listen_port": cfg.CONF.api.port,
57-
"listen_ssl": cfg.CONF.api.use_ssl,
58-
"type": "active",
41+
def main():
42+
common_setup = {
43+
"register_mq_exchanges": True,
44+
"register_internal_trigger_types": True,
5945
}
6046

61-
common_setup(
62-
service=API,
63-
config=config,
64-
setup_db=True,
65-
register_mq_exchanges=True,
66-
register_signal_handlers=True,
67-
register_internal_trigger_types=True,
68-
service_registry=True,
69-
capabilities=capabilities,
70-
)
71-
72-
# Additional pre-run time checks
73-
validate_auth_cookie_is_correctly_configured()
74-
validate_rbac_is_correctly_configured()
75-
76-
77-
def _run_server():
78-
host = cfg.CONF.api.host
79-
port = cfg.CONF.api.port
80-
use_ssl = cfg.CONF.api.use_ssl
81-
82-
cert_file_path = os.path.realpath(cfg.CONF.api.cert)
83-
key_file_path = os.path.realpath(cfg.CONF.api.key)
84-
85-
if use_ssl and not os.path.isfile(cert_file_path):
86-
raise ValueError('Certificate file "%s" doesn\'t exist' % (cert_file_path))
87-
88-
if use_ssl and not os.path.isfile(key_file_path):
89-
raise ValueError('Private key file "%s" doesn\'t exist' % (key_file_path))
90-
91-
LOG.info(
92-
"(PID=%s) ST2 API is serving on %s://%s:%s.",
93-
os.getpid(),
94-
"https" if use_ssl else "http",
95-
host,
96-
port,
97-
)
98-
99-
max_pool_size = eventlet.wsgi.DEFAULT_MAX_SIMULTANEOUS_REQUESTS
100-
worker_pool = eventlet.GreenPool(max_pool_size)
101-
sock = eventlet.listen((host, port))
102-
103-
if use_ssl:
104-
sock = eventlet.wrap_ssl(
105-
sock, certfile=cert_file_path, keyfile=key_file_path, server_side=True
106-
)
107-
108-
wsgi.server(
109-
sock, app.setup_app(), custom_pool=worker_pool, log=LOG, log_output=False
47+
pre_run_checks = [
48+
validate_auth_cookie_is_correctly_configured,
49+
validate_rbac_is_correctly_configured,
50+
]
51+
52+
api.run(
53+
service_name="api",
54+
app_config=config,
55+
cfg=cfg.CONF.api,
56+
app=app,
57+
log=LOG,
58+
use_custom_pool=False,
59+
log_output=False,
60+
common_setup_kwargs=common_setup,
61+
pre_run_checks=pre_run_checks,
11062
)
111-
return 0
112-
113-
114-
def _teardown():
115-
common_teardown()
116-
117-
118-
def main():
119-
try:
120-
_setup()
121-
return _run_server()
122-
except SystemExit as exit_code:
123-
deregister_service(API)
124-
sys.exit(exit_code)
125-
except Exception:
126-
LOG.exception("(PID=%s) ST2 API quit due to exception.", os.getpid())
127-
return 1
128-
finally:
129-
_teardown()

st2api/st2api/config.py

+5-32
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,22 @@
2424
from oslo_config import cfg
2525

2626
import st2common.config as common_config
27-
from st2common.constants.system import VERSION_STRING
28-
from st2common.constants.system import DEFAULT_CONFIG_FILE_PATH
27+
from st2common.openapi import config
2928

3029
CONF = cfg.CONF
3130
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
3231

3332

3433
def parse_args(args=None):
35-
cfg.CONF(
36-
args=args,
37-
version=VERSION_STRING,
38-
default_config_files=[DEFAULT_CONFIG_FILE_PATH],
39-
)
34+
config.parse_args(args=args)
4035

4136

4237
def register_opts(ignore_errors=False):
43-
_register_common_opts(ignore_errors=ignore_errors)
44-
_register_app_opts(ignore_errors=ignore_errors)
45-
46-
47-
def _register_common_opts(ignore_errors=False):
48-
common_config.register_opts(ignore_errors=ignore_errors)
38+
config.register_opts(_register_app_opts, ignore_errors=ignore_errors)
4939

5040

5141
def get_logging_config_path():
52-
return cfg.CONF.api.logging
42+
return config.get_logging_config_path(cfg.CONF.api)
5343

5444

5545
def _register_app_opts(ignore_errors=False):
@@ -76,30 +66,13 @@ def _register_app_opts(ignore_errors=False):
7666
pecan_opts, group="api_pecan", ignore_errors=ignore_errors
7767
)
7868

79-
api_opts = [
80-
cfg.BoolOpt("debug", default=False),
81-
cfg.StrOpt(
82-
"logging",
83-
default="/etc/st2/logging.api.conf",
84-
help="location of the logging.conf file",
85-
),
69+
api_opts = config.get_base_opts("api") + [
8670
cfg.IntOpt(
8771
"max_page_size",
8872
default=100,
8973
help="Maximum limit (page size) argument which can be "
9074
"specified by the user in a query string.",
9175
),
92-
cfg.BoolOpt("use_ssl", default=False, help="Specify to enable SSL / TLS mode"),
93-
cfg.StrOpt(
94-
"cert",
95-
default="/etc/apache2/ssl/mycert.crt",
96-
help='Path to the SSL certificate file. Only used when "use_ssl" is specified.',
97-
),
98-
cfg.StrOpt(
99-
"key",
100-
default="/etc/apache2/ssl/mycert.key",
101-
help='Path to the SSL private key file. Only used when "use_ssl" is specified.',
102-
),
10376
]
10477

10578
common_config.do_register_opts(api_opts, group="api", ignore_errors=ignore_errors)

0 commit comments

Comments
 (0)