cavisson-pythonagent 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cavisson_pythonagent-0.0.1.dist-info/METADATA +32 -0
- cavisson_pythonagent-0.0.1.dist-info/RECORD +180 -0
- cavisson_pythonagent-0.0.1.dist-info/WHEEL +5 -0
- cavisson_pythonagent-0.0.1.dist-info/licenses/LICENSE +19 -0
- cavisson_pythonagent-0.0.1.dist-info/top_level.txt +1 -0
- pythonagent/__init__.py +22 -0
- pythonagent/agent/__init__.py +219 -0
- pythonagent/agent/internal/__init__.py +1 -0
- pythonagent/agent/internal/agent.py +1651 -0
- pythonagent/agent/internal/framesinfo.py +152 -0
- pythonagent/agent/internal/heap_dump.py +39 -0
- pythonagent/agent/internal/intercept_module.py +70 -0
- pythonagent/agent/internal/logs.py +122 -0
- pythonagent/agent/internal/metadata/__init__.py +0 -0
- pythonagent/agent/internal/metadata/agent_meta_data.py +276 -0
- pythonagent/agent/internal/proc_compat.py +75 -0
- pythonagent/agent/internal/profile.py +47 -0
- pythonagent/agent/internal/provider.py +83 -0
- pythonagent/agent/internal/thread_dump.py +85 -0
- pythonagent/agent/internal/udp.py +245 -0
- pythonagent/agent/internal/udp_message.py +800 -0
- pythonagent/agent/probes/Instrumentation/__init__.py +340 -0
- pythonagent/agent/probes/Instrumentation/find.py +243 -0
- pythonagent/agent/probes/Instrumentation/module_version_resolver.py +155 -0
- pythonagent/agent/probes/Instrumentation/new_parser.py +64 -0
- pythonagent/agent/probes/Instrumentation/parser.py +129 -0
- pythonagent/agent/probes/__init__.py +219 -0
- pythonagent/agent/probes/base.py +303 -0
- pythonagent/agent/probes/cache/__init__.py +51 -0
- pythonagent/agent/probes/cache/redis.py +119 -0
- pythonagent/agent/probes/cache/redis_asyncio.py +83 -0
- pythonagent/agent/probes/coroutines/__init__.py +1 -0
- pythonagent/agent/probes/coroutines/asyncio.py +63 -0
- pythonagent/agent/probes/elasticdb/__init__.py +7 -0
- pythonagent/agent/probes/elasticdb/aelastic.py +54 -0
- pythonagent/agent/probes/frameworks/__init__.py +27 -0
- pythonagent/agent/probes/frameworks/agentprofiler.py +105 -0
- pythonagent/agent/probes/frameworks/aiohttp_web.py +155 -0
- pythonagent/agent/probes/frameworks/aisess.py +151 -0
- pythonagent/agent/probes/frameworks/asgi.py +340 -0
- pythonagent/agent/probes/frameworks/bottle.py +27 -0
- pythonagent/agent/probes/frameworks/cherry.py +25 -0
- pythonagent/agent/probes/frameworks/django.py +128 -0
- pythonagent/agent/probes/frameworks/falcon.py +21 -0
- pythonagent/agent/probes/frameworks/fastapi.py +35 -0
- pythonagent/agent/probes/frameworks/flask.py +30 -0
- pythonagent/agent/probes/frameworks/pyramid.py +56 -0
- pythonagent/agent/probes/frameworks/test.py +108 -0
- pythonagent/agent/probes/frameworks/tornado_async_web.py +117 -0
- pythonagent/agent/probes/frameworks/tornado_web.py +133 -0
- pythonagent/agent/probes/frameworks/wsgi.py +353 -0
- pythonagent/agent/probes/grpc/__init__.py +76 -0
- pythonagent/agent/probes/grpc/client_interceptor.py +132 -0
- pythonagent/agent/probes/grpc/server_interceptor.py +129 -0
- pythonagent/agent/probes/havoc/__init__.py +0 -0
- pythonagent/agent/probes/havoc/custom_memory_stress.py +186 -0
- pythonagent/agent/probes/havoc/custom_thread_stress.py +187 -0
- pythonagent/agent/probes/havoc/havoc_constants.py +218 -0
- pythonagent/agent/probes/havoc/havoc_manager.py +981 -0
- pythonagent/agent/probes/http/__init__.py +49 -0
- pythonagent/agent/probes/http/aiohttp_client.py +59 -0
- pythonagent/agent/probes/http/boto.py +12 -0
- pythonagent/agent/probes/http/httplib.py +110 -0
- pythonagent/agent/probes/http/httpx_client.py +116 -0
- pythonagent/agent/probes/http/requests.py +15 -0
- pythonagent/agent/probes/http/tornado_httpclient.py +85 -0
- pythonagent/agent/probes/http/urllib3.py +16 -0
- pythonagent/agent/probes/langchain/__init__.py +21 -0
- pythonagent/agent/probes/langchain/base_tool.py +95 -0
- pythonagent/agent/probes/langchain/langchain_community.py +136 -0
- pythonagent/agent/probes/langchain/langchain_core.py +32 -0
- pythonagent/agent/probes/langchain/langchain_openai.py +110 -0
- pythonagent/agent/probes/logging/__init__.py +106 -0
- pythonagent/agent/probes/message_brokers/__init__.py +4 -0
- pythonagent/agent/probes/message_brokers/pika.py +126 -0
- pythonagent/agent/probes/mongodb/__init__.py +6 -0
- pythonagent/agent/probes/mongodb/pymongo.py +286 -0
- pythonagent/agent/probes/openai/__init__.py +3 -0
- pythonagent/agent/probes/openai/openai.py +797 -0
- pythonagent/agent/probes/span.py +101 -0
- pythonagent/agent/probes/sql/__init__.py +13 -0
- pythonagent/agent/probes/sql/botocores3.py +51 -0
- pythonagent/agent/probes/sql/dbapi.py +285 -0
- pythonagent/agent/probes/sql/dynamodb.py +90 -0
- pythonagent/agent/probes/sql/mysql_connector.py +24 -0
- pythonagent/agent/probes/sql/mysql_connector_cext.py +24 -0
- pythonagent/agent/probes/sql/mysqldb.py +43 -0
- pythonagent/agent/probes/sql/psycopg2.py +174 -0
- pythonagent/agent/probes/sql/pymysql.py +25 -0
- pythonagent/bootstrap/__init__.py +0 -0
- pythonagent/bootstrap/cav_gunicorn.py +26 -0
- pythonagent/bootstrap/cavagent_lambda_wrapper.py +291 -0
- pythonagent/bootstrap/run.py +47 -0
- pythonagent/bootstrap/sitecustomize.py +287 -0
- pythonagent/cavisson/netdiagnostics/CavAgent/instrumentationprofile.json +26 -0
- pythonagent/cavisson/netdiagnostics/CavAgent/interceptor_points.txt +29 -0
- pythonagent/cavisson/netdiagnostics/python/CavAgent/instrumentationprofile.json +42 -0
- pythonagent/cavisson/netdiagnostics/python/CavAgent/interceptor_points.txt +29 -0
- pythonagent/cavisson/netdiagnostics/python/config/ndsettings.conf +6 -0
- pythonagent/config.py +279 -0
- pythonagent/find.py +72 -0
- pythonagent/find_mod_cls_name.py +54 -0
- pythonagent/lang.py +131 -0
- pythonagent/lib.py +91 -0
- pythonagent/main/__init__.py +0 -0
- pythonagent/main/pytrace/__init__.py +79 -0
- pythonagent/main/pytrace/commands/__init__.py +0 -0
- pythonagent/main/pytrace/commands/auto_discovery.py +25 -0
- pythonagent/main/pytrace/commands/run.py +401 -0
- pythonagent/main/pytrace/pytrace.py +133 -0
- pythonagent/main/wsgi.py +6 -0
- pythonagent/main.py +27 -0
- pythonagent/run.py +46 -0
- pythonagent/sqins.py +8 -0
- pythonagent/test.py +73 -0
- pythonagent/utils.py +168 -0
- pythonagent/vendor/__init__.py +0 -0
- pythonagent/vendor/pympler/__init__.py +1 -0
- pythonagent/vendor/pympler/asizeof.py +2810 -0
- pythonagent/vendor/pympler/charts.py +62 -0
- pythonagent/vendor/pympler/classtracker.py +590 -0
- pythonagent/vendor/pympler/classtracker_stats.py +780 -0
- pythonagent/vendor/pympler/garbagegraph.py +80 -0
- pythonagent/vendor/pympler/mprofile.py +97 -0
- pythonagent/vendor/pympler/muppy.py +275 -0
- pythonagent/vendor/pympler/panels.py +115 -0
- pythonagent/vendor/pympler/process.py +238 -0
- pythonagent/vendor/pympler/py.typed +0 -0
- pythonagent/vendor/pympler/refbrowser.py +451 -0
- pythonagent/vendor/pympler/refgraph.py +350 -0
- pythonagent/vendor/pympler/summary.py +321 -0
- pythonagent/vendor/pympler/tracker.py +267 -0
- pythonagent/vendor/pympler/util/__init__.py +0 -0
- pythonagent/vendor/pympler/util/bottle.py +3809 -0
- pythonagent/vendor/pympler/util/compat.py +23 -0
- pythonagent/vendor/pympler/util/stringutils.py +77 -0
- pythonagent/vendor/pympler/web.py +346 -0
- pythonagent/vendor/werkzeug/__init__.py +20 -0
- pythonagent/vendor/werkzeug/_compat.py +228 -0
- pythonagent/vendor/werkzeug/_internal.py +473 -0
- pythonagent/vendor/werkzeug/_reloader.py +341 -0
- pythonagent/vendor/werkzeug/datastructures.py +3120 -0
- pythonagent/vendor/werkzeug/debug/__init__.py +498 -0
- pythonagent/vendor/werkzeug/debug/console.py +218 -0
- pythonagent/vendor/werkzeug/debug/repr.py +297 -0
- pythonagent/vendor/werkzeug/debug/tbtools.py +628 -0
- pythonagent/vendor/werkzeug/exceptions.py +829 -0
- pythonagent/vendor/werkzeug/filesystem.py +64 -0
- pythonagent/vendor/werkzeug/formparser.py +584 -0
- pythonagent/vendor/werkzeug/http.py +1307 -0
- pythonagent/vendor/werkzeug/local.py +420 -0
- pythonagent/vendor/werkzeug/middleware/__init__.py +25 -0
- pythonagent/vendor/werkzeug/middleware/dispatcher.py +66 -0
- pythonagent/vendor/werkzeug/middleware/http_proxy.py +219 -0
- pythonagent/vendor/werkzeug/middleware/lint.py +408 -0
- pythonagent/vendor/werkzeug/middleware/profiler.py +132 -0
- pythonagent/vendor/werkzeug/middleware/proxy_fix.py +169 -0
- pythonagent/vendor/werkzeug/middleware/shared_data.py +293 -0
- pythonagent/vendor/werkzeug/posixemulation.py +117 -0
- pythonagent/vendor/werkzeug/routing.py +2210 -0
- pythonagent/vendor/werkzeug/security.py +249 -0
- pythonagent/vendor/werkzeug/serving.py +1117 -0
- pythonagent/vendor/werkzeug/test.py +1123 -0
- pythonagent/vendor/werkzeug/testapp.py +241 -0
- pythonagent/vendor/werkzeug/urls.py +1138 -0
- pythonagent/vendor/werkzeug/useragents.py +202 -0
- pythonagent/vendor/werkzeug/utils.py +778 -0
- pythonagent/vendor/werkzeug/wrappers/__init__.py +36 -0
- pythonagent/vendor/werkzeug/wrappers/accept.py +50 -0
- pythonagent/vendor/werkzeug/wrappers/auth.py +33 -0
- pythonagent/vendor/werkzeug/wrappers/base_request.py +673 -0
- pythonagent/vendor/werkzeug/wrappers/base_response.py +700 -0
- pythonagent/vendor/werkzeug/wrappers/common_descriptors.py +341 -0
- pythonagent/vendor/werkzeug/wrappers/cors.py +100 -0
- pythonagent/vendor/werkzeug/wrappers/etag.py +304 -0
- pythonagent/vendor/werkzeug/wrappers/json.py +145 -0
- pythonagent/vendor/werkzeug/wrappers/request.py +49 -0
- pythonagent/vendor/werkzeug/wrappers/response.py +84 -0
- pythonagent/vendor/werkzeug/wrappers/user_agent.py +14 -0
- pythonagent/vendor/werkzeug/wsgi.py +1000 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import errno
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
#from agent.internal.proxy import Proxy
|
|
5
|
+
from pythonagent.main.pytrace import CommandInvocationError, CommandExecutionError
|
|
6
|
+
|
|
7
|
+
USAGE = "run <command> [args...]"
|
|
8
|
+
|
|
9
|
+
ABOUT = """Run a program with the agent enabled.
|
|
10
|
+
|
|
11
|
+
Use this command to instrument a Python application. If <command> is not the
|
|
12
|
+
path to an executable, the command is looked for in your PATH. The command may
|
|
13
|
+
be a Python interpreter or a supported server that embeds Python (like uwsgi
|
|
14
|
+
and gunicorn).
|
|
15
|
+
|
|
16
|
+
For example, if you normally run your application as below commands:
|
|
17
|
+
|
|
18
|
+
1) python manage.py runserver --norelaod 10:20.0.117:6062
|
|
19
|
+
2) gunicorn -w 4 -b unix:acme.sock acme.app:app
|
|
20
|
+
|
|
21
|
+
You can run the same application instrumented by pythonagent with below commands:
|
|
22
|
+
|
|
23
|
+
1) cavagent run python manage.py runserver --norelaod 10:20.0.117:6062
|
|
24
|
+
2) cavagent run -- gunicorn -w 4 -b unix:acme.sock acme.app:app
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
The agent requires the TestRun to be running. If it
|
|
28
|
+
is not running, your application will not be start.
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
OPTION = {
|
|
33
|
+
'cli': 'run in CLI mode',
|
|
34
|
+
|
|
35
|
+
# 'no-watchdog': 'disable the watchdog when auto-starting proxy',
|
|
36
|
+
|
|
37
|
+
'config-file': {
|
|
38
|
+
'short': 'c',
|
|
39
|
+
'help': 'the config file to use',
|
|
40
|
+
'value': True,
|
|
41
|
+
'value_help': '<file>',
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
'app': {
|
|
45
|
+
'short': 'a',
|
|
46
|
+
'help': 'the name of the app',
|
|
47
|
+
'value': True,
|
|
48
|
+
'value_help': '<app>',
|
|
49
|
+
},
|
|
50
|
+
'tier': {
|
|
51
|
+
'short': 't',
|
|
52
|
+
'help': 'the name of the tier',
|
|
53
|
+
'value': True,
|
|
54
|
+
'value_help': '<tier>',
|
|
55
|
+
},
|
|
56
|
+
# 'node': {
|
|
57
|
+
# 'short': 'n',
|
|
58
|
+
# 'help': 'the name of the node',
|
|
59
|
+
# 'value': True,
|
|
60
|
+
# 'value_help': '<node>',
|
|
61
|
+
# },
|
|
62
|
+
|
|
63
|
+
# 'controller': {
|
|
64
|
+
# 'short': 'h',
|
|
65
|
+
# 'help': 'the host (and optionally port) of the controller',
|
|
66
|
+
# 'value': True,
|
|
67
|
+
# 'value_help': '<host>[:<port>]',
|
|
68
|
+
# },
|
|
69
|
+
|
|
70
|
+
# 'ssl': {
|
|
71
|
+
# 'help': 'pass to use SSL with the controller',
|
|
72
|
+
# },
|
|
73
|
+
#
|
|
74
|
+
# 'no-ssl': {
|
|
75
|
+
# 'help': 'pass to disable SSL with the controller (the default)',
|
|
76
|
+
# },
|
|
77
|
+
|
|
78
|
+
'proxyMode': {
|
|
79
|
+
'short': 'pmode',
|
|
80
|
+
'help': 'proxyMode',
|
|
81
|
+
'value': True,
|
|
82
|
+
'value_help': '<proxyMode> value - [0/1]',
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
'proxyConType': {
|
|
86
|
+
'short': 'pctype',
|
|
87
|
+
'help': 'please enter proxy con type ',
|
|
88
|
+
'value': True,
|
|
89
|
+
'value_help': '<proxyConType> value - [0/1]',
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
'proxyIP': {
|
|
93
|
+
'short': 'pip',
|
|
94
|
+
'help': 'please enter proxy IP host address',
|
|
95
|
+
'value': True,
|
|
96
|
+
'value_help': '<proxyConType>',
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
'proxyPort': {
|
|
100
|
+
'short': 'pport',
|
|
101
|
+
'help': 'please enter proxy port number ',
|
|
102
|
+
'value': True,
|
|
103
|
+
'value_help': '<proxyPort>',
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
# Internal / undocumented options
|
|
107
|
+
|
|
108
|
+
# 'run-proxy-script': {
|
|
109
|
+
# 'help': False, # "Path to runProxy script"
|
|
110
|
+
# 'value': True,
|
|
111
|
+
# },
|
|
112
|
+
#
|
|
113
|
+
# 'proxy-args': {
|
|
114
|
+
# 'help': False, # "Command line arguments to pass to runProxy"
|
|
115
|
+
# 'value': True,
|
|
116
|
+
# },
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ---------------------------------------------------------------------------
|
|
122
|
+
# uWSGI argument / config-file rewriting helpers (Approaches 1-6)
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
def _get_agent_wsgi_path():
|
|
126
|
+
"""Return the absolute filesystem path to pythonagent/main/wsgi.py."""
|
|
127
|
+
import pythonagent.main.wsgi as _m
|
|
128
|
+
return os.path.abspath(_m.__file__.replace('.pyc', '.py'))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _parse_uwsgi_ini(path):
|
|
132
|
+
"""Parse a uWSGI INI config file and return the [uwsgi] section as a dict."""
|
|
133
|
+
import configparser
|
|
134
|
+
parser = configparser.RawConfigParser()
|
|
135
|
+
parser.read(path)
|
|
136
|
+
section = 'uwsgi'
|
|
137
|
+
if not parser.has_section(section):
|
|
138
|
+
return {}
|
|
139
|
+
return dict(parser.items(section))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _parse_uwsgi_xml(path):
|
|
143
|
+
"""Parse a uWSGI XML config file and return top-level tags as a dict."""
|
|
144
|
+
import xml.etree.ElementTree as ET
|
|
145
|
+
try:
|
|
146
|
+
root = ET.parse(path).getroot()
|
|
147
|
+
return {child.tag: (child.text or '') for child in root}
|
|
148
|
+
except Exception:
|
|
149
|
+
return {}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _parse_uwsgi_yaml(path):
|
|
153
|
+
"""Parse a uWSGI YAML config file and return the 'uwsgi' key as a dict.
|
|
154
|
+
Returns an empty dict silently when PyYAML is not installed."""
|
|
155
|
+
try:
|
|
156
|
+
import yaml
|
|
157
|
+
with open(path) as f:
|
|
158
|
+
data = yaml.safe_load(f)
|
|
159
|
+
return data.get('uwsgi', {}) if isinstance(data, dict) else {}
|
|
160
|
+
except ImportError:
|
|
161
|
+
return {}
|
|
162
|
+
except Exception:
|
|
163
|
+
return {}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _parse_uwsgi_json(path):
|
|
167
|
+
"""Parse a uWSGI JSON config file and return the 'uwsgi' key as a dict."""
|
|
168
|
+
import json
|
|
169
|
+
try:
|
|
170
|
+
with open(path) as f:
|
|
171
|
+
data = json.load(f)
|
|
172
|
+
return data.get('uwsgi', {}) if isinstance(data, dict) else {}
|
|
173
|
+
except Exception:
|
|
174
|
+
return {}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _apply_uwsgi_config(cfg, args, environ):
|
|
178
|
+
"""Given a dict parsed from a uWSGI config file, extract the WSGI app
|
|
179
|
+
location and inject it into environ as CAV_* vars. Appends a
|
|
180
|
+
--wsgi-file override pointing at the agent entry point so uWSGI loads
|
|
181
|
+
the agent wrapper instead of the user app directly."""
|
|
182
|
+
agent_wsgi = _get_agent_wsgi_path()
|
|
183
|
+
if 'module' in cfg and 'CAV_WSGI_MODULE' not in environ:
|
|
184
|
+
environ['CAV_WSGI_MODULE'] = cfg['module']
|
|
185
|
+
args += ['--wsgi-file', agent_wsgi]
|
|
186
|
+
elif 'wsgi-file' in cfg and 'CAV_WSGI_SCRIPT_ALIAS' not in environ:
|
|
187
|
+
environ['CAV_WSGI_SCRIPT_ALIAS'] = cfg['wsgi-file']
|
|
188
|
+
args += ['--wsgi-file', agent_wsgi]
|
|
189
|
+
if 'callable' in cfg and 'CAV_WSGI_CALLABLE_OBJECT' not in environ:
|
|
190
|
+
environ['CAV_WSGI_CALLABLE_OBJECT'] = cfg['callable']
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _rewrite_uwsgi_args(args, environ):
|
|
194
|
+
"""Scan uWSGI command-line arguments and rewrite them so that:
|
|
195
|
+
|
|
196
|
+
* --wsgi-file → value saved to CAV_WSGI_SCRIPT_ALIAS; replaced with the
|
|
197
|
+
agent's pythonagent/main/wsgi.py entry point.
|
|
198
|
+
* --module/-w → value saved to CAV_WSGI_MODULE; arg replaced with an
|
|
199
|
+
equivalent --wsgi-file pointing at the agent entry point.
|
|
200
|
+
* --callable → value saved to CAV_WSGI_CALLABLE_OBJECT (kept in args).
|
|
201
|
+
* --ini/--xml/--yaml/--json → config file parsed; WSGI keys extracted and
|
|
202
|
+
--wsgi-file override appended (Approaches 3-6).
|
|
203
|
+
|
|
204
|
+
All other uWSGI arguments (--processes, --socket, --master …) are left
|
|
205
|
+
untouched so uWSGI continues to function normally.
|
|
206
|
+
|
|
207
|
+
Returns (rewritten_args, updated_environ).
|
|
208
|
+
"""
|
|
209
|
+
if not args or os.path.basename(args[0]) not in ('uwsgi', 'uwsgi3'):
|
|
210
|
+
return args, environ
|
|
211
|
+
|
|
212
|
+
args = list(args)
|
|
213
|
+
environ = dict(environ) # work on a copy; caller replaces os.environ at the end
|
|
214
|
+
agent_wsgi = _get_agent_wsgi_path()
|
|
215
|
+
i = 1 # args[0] is the uwsgi binary itself
|
|
216
|
+
|
|
217
|
+
while i < len(args):
|
|
218
|
+
arg = args[i]
|
|
219
|
+
|
|
220
|
+
# ---- Approach 1: --wsgi-file ----------------------------------------
|
|
221
|
+
if arg in ('--wsgi-file', '--wsgi') and i + 1 < len(args):
|
|
222
|
+
environ.setdefault('CAV_WSGI_SCRIPT_ALIAS', args[i + 1])
|
|
223
|
+
args[i + 1] = agent_wsgi
|
|
224
|
+
i += 2
|
|
225
|
+
|
|
226
|
+
elif arg.startswith('--wsgi-file=') or arg.startswith('--wsgi='):
|
|
227
|
+
key, val = arg.split('=', 1)
|
|
228
|
+
environ.setdefault('CAV_WSGI_SCRIPT_ALIAS', val)
|
|
229
|
+
args[i] = key + '=' + agent_wsgi
|
|
230
|
+
i += 1
|
|
231
|
+
|
|
232
|
+
# ---- Approach 1: --callable -----------------------------------------
|
|
233
|
+
elif arg == '--callable' and i + 1 < len(args):
|
|
234
|
+
environ.setdefault('CAV_WSGI_CALLABLE_OBJECT', args[i + 1])
|
|
235
|
+
i += 2
|
|
236
|
+
|
|
237
|
+
elif arg.startswith('--callable='):
|
|
238
|
+
environ.setdefault('CAV_WSGI_CALLABLE_OBJECT', arg.split('=', 1)[1])
|
|
239
|
+
i += 1
|
|
240
|
+
|
|
241
|
+
# ---- Approach 2: --module / -w --------------------------------------
|
|
242
|
+
elif arg in ('--module', '-w') and i + 1 < len(args):
|
|
243
|
+
environ.setdefault('CAV_WSGI_MODULE', args[i + 1])
|
|
244
|
+
args[i] = '--wsgi-file'
|
|
245
|
+
args[i + 1] = agent_wsgi
|
|
246
|
+
i += 2
|
|
247
|
+
|
|
248
|
+
elif arg.startswith('--module='):
|
|
249
|
+
environ.setdefault('CAV_WSGI_MODULE', arg.split('=', 1)[1])
|
|
250
|
+
args[i] = '--wsgi-file=' + agent_wsgi
|
|
251
|
+
i += 1
|
|
252
|
+
|
|
253
|
+
# ---- Approach 3: --ini ----------------------------------------------
|
|
254
|
+
elif arg == '--ini' and i + 1 < len(args):
|
|
255
|
+
_apply_uwsgi_config(_parse_uwsgi_ini(args[i + 1]), args, environ)
|
|
256
|
+
i += 2
|
|
257
|
+
|
|
258
|
+
elif arg.startswith('--ini='):
|
|
259
|
+
_apply_uwsgi_config(_parse_uwsgi_ini(arg.split('=', 1)[1]), args, environ)
|
|
260
|
+
i += 1
|
|
261
|
+
|
|
262
|
+
# ---- Approach 4: --xml ----------------------------------------------
|
|
263
|
+
elif arg == '--xml' and i + 1 < len(args):
|
|
264
|
+
_apply_uwsgi_config(_parse_uwsgi_xml(args[i + 1]), args, environ)
|
|
265
|
+
i += 2
|
|
266
|
+
|
|
267
|
+
elif arg.startswith('--xml='):
|
|
268
|
+
_apply_uwsgi_config(_parse_uwsgi_xml(arg.split('=', 1)[1]), args, environ)
|
|
269
|
+
i += 1
|
|
270
|
+
|
|
271
|
+
# ---- Approach 5: --yaml ---------------------------------------------
|
|
272
|
+
elif arg == '--yaml' and i + 1 < len(args):
|
|
273
|
+
_apply_uwsgi_config(_parse_uwsgi_yaml(args[i + 1]), args, environ)
|
|
274
|
+
i += 2
|
|
275
|
+
|
|
276
|
+
elif arg.startswith('--yaml='):
|
|
277
|
+
_apply_uwsgi_config(_parse_uwsgi_yaml(arg.split('=', 1)[1]), args, environ)
|
|
278
|
+
i += 1
|
|
279
|
+
|
|
280
|
+
# ---- Approach 6: --json ---------------------------------------------
|
|
281
|
+
elif arg == '--json' and i + 1 < len(args):
|
|
282
|
+
_apply_uwsgi_config(_parse_uwsgi_json(args[i + 1]), args, environ)
|
|
283
|
+
i += 2
|
|
284
|
+
|
|
285
|
+
elif arg.startswith('--json='):
|
|
286
|
+
_apply_uwsgi_config(_parse_uwsgi_json(arg.split('=', 1)[1]), args, environ)
|
|
287
|
+
i += 1
|
|
288
|
+
|
|
289
|
+
else:
|
|
290
|
+
i += 1
|
|
291
|
+
|
|
292
|
+
return args, environ
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
# ---------------------------------------------------------------------------
|
|
296
|
+
|
|
297
|
+
def command(options, args):
|
|
298
|
+
|
|
299
|
+
'''
|
|
300
|
+
processname = 'TestRun'
|
|
301
|
+
tmp = os.popen("nsu_show_netstorm").read()
|
|
302
|
+
proccount = tmp.count(processname)
|
|
303
|
+
|
|
304
|
+
if proccount > 0:
|
|
305
|
+
print("TestRun is running...")
|
|
306
|
+
else:
|
|
307
|
+
print("ERROR!! TestRun is not running on this machine !!!\nKindly start the TestRun and try again...")
|
|
308
|
+
sys.exit(1)
|
|
309
|
+
'''
|
|
310
|
+
import bootstrap
|
|
311
|
+
pythonpath = [os.path.dirname(bootstrap.__file__), '.']
|
|
312
|
+
|
|
313
|
+
if not args:
|
|
314
|
+
raise CommandInvocationError('missing command: run <options> -- <command> [args...]')
|
|
315
|
+
|
|
316
|
+
environ = os.environ
|
|
317
|
+
|
|
318
|
+
if 'PYTHONPATH' in environ:
|
|
319
|
+
pythonpath.append(environ['PYTHONPATH'])
|
|
320
|
+
|
|
321
|
+
environ['PYTHONPATH'] = ':'.join(pythonpath)
|
|
322
|
+
#environ['CAV_APP_AGENT_ENV']= "NATIVE"
|
|
323
|
+
#environ['LD_LIBRARY_PATH'] = "/usr/local/lib"
|
|
324
|
+
environ['LD_PRELOAD'] = "libcavapr-1.so.0 libwebsockets.so"
|
|
325
|
+
#print('NDHOME set as ',environ.get('NDHOME'))
|
|
326
|
+
print("NDHOME Environment variable :", environ.get('NDHOME'))
|
|
327
|
+
if environ.get('NDHOME') is None:
|
|
328
|
+
#environ['NDHOME'] = "/opt/cavisson/netdiagnostics"
|
|
329
|
+
environ['NDHOME'] = "/opt/cavisson/netdiagnostics"
|
|
330
|
+
print("Taking Default NDHOME path",environ.get('NDHOME'))
|
|
331
|
+
environ['CAV_RUNNING_MODE'] = '0'
|
|
332
|
+
|
|
333
|
+
if 'config-file' in options:
|
|
334
|
+
environ['CAV_CONFIG_FILE'] = options['config-file']
|
|
335
|
+
if 'app' in options:
|
|
336
|
+
environ['CAV_APP_NAME'] = options['app']
|
|
337
|
+
if 'tier' in options:
|
|
338
|
+
environ['CAV_TIER_NAME'] = options['tier']
|
|
339
|
+
if 'node' in options:
|
|
340
|
+
environ['CAV_NODE_NAME'] = options['node']
|
|
341
|
+
if 'proxyMode' in options:
|
|
342
|
+
environ['CAV_APP_AGENT_PROXYMODE'] = options['proxyMode']
|
|
343
|
+
if logger.isEnabledFor(logging.INFO):
|
|
344
|
+
logger.info("Using proxy mode from env %s=%s", 'CAV_APP_AGENT_PROXYMODE', environ['CAV_APP_AGENT_PROXYMODE'])
|
|
345
|
+
if 'proxyConType' in options:
|
|
346
|
+
environ['CAV_proxyConType'] = options['proxyConType']
|
|
347
|
+
if 'proxyIP' in options:
|
|
348
|
+
environ['CAV_APP_AGENT_PROXYIP'] = options['proxyIP']
|
|
349
|
+
if logger.isEnabledFor(logging.INFO):
|
|
350
|
+
logger.info("Using proxy IP from env %s=%s", 'CAV_APP_AGENT_PROXYIP', environ['CAV_APP_AGENT_PROXYIP'])
|
|
351
|
+
if 'proxyPort' in options:
|
|
352
|
+
environ['CAV_APP_AGENT_PROXYPORT'] = options['proxyPort']
|
|
353
|
+
if logger.isEnabledFor(logging.INFO):
|
|
354
|
+
logger.info("Using proxy port from env %s=%s", 'CAV_APP_AGENT_PROXYPORT', environ['CAV_APP_AGENT_PROXYPORT'])
|
|
355
|
+
environ['nd_init_done'] = '0'
|
|
356
|
+
|
|
357
|
+
# if 'ssl' in options:
|
|
358
|
+
# environ['APPD_SSL_ENABLED'] = 'on'
|
|
359
|
+
# elif 'no-ssl' in options:
|
|
360
|
+
# environ['APPD_SSL_ENABLED'] = 'off'
|
|
361
|
+
|
|
362
|
+
# if 'controller' in options:
|
|
363
|
+
# value = options['controller']
|
|
364
|
+
#
|
|
365
|
+
# if ':' in value:
|
|
366
|
+
# host, port = value.split(':', 1)
|
|
367
|
+
# environ['APPD_CONTROLLER_HOST'] = host
|
|
368
|
+
# environ['APPD_CONTROLLER_PORT'] = port
|
|
369
|
+
# else:
|
|
370
|
+
# environ['APPD_CONTROLLER_HOST'] = value
|
|
371
|
+
|
|
372
|
+
# if 'use-manual-proxy' not in options:
|
|
373
|
+
# proxy_args = []
|
|
374
|
+
#
|
|
375
|
+
# if 'no-watchdog' in options:
|
|
376
|
+
# proxy_args.append('--no-watchdog')
|
|
377
|
+
#
|
|
378
|
+
# if 'run-proxy-script' in options:
|
|
379
|
+
# proxy_args.append('--run-proxy-script')
|
|
380
|
+
# proxy_args.append(options['run-proxy-script'])
|
|
381
|
+
#
|
|
382
|
+
# if 'proxy-args' in options:
|
|
383
|
+
# proxy_args.extend(shlex.split(options['proxy-args']))
|
|
384
|
+
|
|
385
|
+
# proxy.start(proxy_args)
|
|
386
|
+
|
|
387
|
+
try:
|
|
388
|
+
# Approaches 1-6: rewrite uWSGI args so the agent's wsgi.py becomes the
|
|
389
|
+
# entry point and the real app location is saved to CAV_WSGI_* env vars.
|
|
390
|
+
args, environ = _rewrite_uwsgi_args(args, environ)
|
|
391
|
+
|
|
392
|
+
os.execvpe(args[0], args, environ)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
except OSError as exc:
|
|
396
|
+
if exc.errno == errno.ENOENT:
|
|
397
|
+
raise CommandExecutionError('%s: no such file or directory' % args[0])
|
|
398
|
+
elif exc.errno == errno.EPERM:
|
|
399
|
+
raise CommandExecutionError('%s: permission denied' % args[0])
|
|
400
|
+
raise
|
|
401
|
+
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Copyright (c) cavisson, Inc., and its affiliates
|
|
2
|
+
# 2015
|
|
3
|
+
# All Rights Reserved
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
import sys,os
|
|
9
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname( __file__ ))))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
from lang import keys
|
|
13
|
+
from pythonagent.main.pytrace import CommandInvocationError, CommandExecutionError, parse_options, HELP_OPTIONS
|
|
14
|
+
from pythonagent.main.pytrace.commands import run,auto_discovery
|
|
15
|
+
|
|
16
|
+
pytrace = os.path.basename(sys.argv[0])
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
COMMANDS = {
|
|
20
|
+
'run': run,
|
|
21
|
+
'auto_discovery': auto_discovery,
|
|
22
|
+
}
|
|
23
|
+
COMMANDS_ORDER = ["run"]
|
|
24
|
+
|
|
25
|
+
HELP_TEMPLATE = """\
|
|
26
|
+
USAGE
|
|
27
|
+
{pytrace} {usage}
|
|
28
|
+
|
|
29
|
+
ABOUT
|
|
30
|
+
{about}"""
|
|
31
|
+
|
|
32
|
+
USAGE = """\
|
|
33
|
+
USAGE
|
|
34
|
+
{pytrace} <command> <args...>
|
|
35
|
+
|
|
36
|
+
ABOUT
|
|
37
|
+
Cavisson Python Agent management utility
|
|
38
|
+
|
|
39
|
+
COMMANDS
|
|
40
|
+
help Print this message
|
|
41
|
+
help <command> Show detailed help for the given pytrace command
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def main():
|
|
46
|
+
if len(sys.argv) < 2:
|
|
47
|
+
print_usage()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
command = sys.argv[1]
|
|
51
|
+
args = sys.argv[2:]
|
|
52
|
+
|
|
53
|
+
if command in HELP_OPTIONS or command == 'help':
|
|
54
|
+
if args:
|
|
55
|
+
print_usage(command=args[0])
|
|
56
|
+
else:
|
|
57
|
+
print_usage()
|
|
58
|
+
|
|
59
|
+
if command not in COMMANDS:
|
|
60
|
+
print_usage(error="%s: unrecognized command" % command)
|
|
61
|
+
|
|
62
|
+
mod = COMMANDS[command]
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
options, args = parse_options(getattr(mod, 'OPTIONS', {}), args)
|
|
66
|
+
|
|
67
|
+
if 'help' in options:
|
|
68
|
+
print_usage(command=command)
|
|
69
|
+
|
|
70
|
+
mod.command(options, args)
|
|
71
|
+
|
|
72
|
+
except CommandInvocationError as exc:
|
|
73
|
+
print_usage(command=command, error=str(exc))
|
|
74
|
+
#print("wrong usage!")
|
|
75
|
+
except CommandExecutionError as exc:
|
|
76
|
+
print(str(exc))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def indent(text, spaces=4):
|
|
80
|
+
indentation = ' ' * spaces
|
|
81
|
+
indented_text = ('\n%s' % indentation).join(text.split('\n'))
|
|
82
|
+
return indented_text
|
|
83
|
+
|
|
84
|
+
def print_usage(command=None, error=None):
|
|
85
|
+
if command and command not in COMMANDS:
|
|
86
|
+
error = '%s: unrecognized command' % command
|
|
87
|
+
command = None
|
|
88
|
+
|
|
89
|
+
if command:
|
|
90
|
+
mod = COMMANDS[command]
|
|
91
|
+
about = indent(mod.ABOUT.format(pytrace=pytrace))
|
|
92
|
+
|
|
93
|
+
print(HELP_TEMPLATE.format(pytrace=pytrace, usage=mod.USAGE, about=about))
|
|
94
|
+
|
|
95
|
+
if getattr(mod, 'OPTIONS', None):
|
|
96
|
+
print('OPTIONS')
|
|
97
|
+
for opt in sorted(keys(mod.OPTIONS)):
|
|
98
|
+
opt_descr = mod.OPTIONS[opt]
|
|
99
|
+
if isinstance(opt_descr, dict):
|
|
100
|
+
if 'short' in opt_descr:
|
|
101
|
+
opt = '%s / -%s' % (opt, opt_descr['short'])
|
|
102
|
+
if opt_descr.get('value', False):
|
|
103
|
+
opt += ' %s' % (opt_descr.get('value_help', ' <value>'))
|
|
104
|
+
|
|
105
|
+
opt_help = opt_descr.get('help', False)
|
|
106
|
+
|
|
107
|
+
if opt_help is False:
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
if opt_descr.get('required', False):
|
|
111
|
+
opt_help = 'REQUIRED: %s' % opt_help
|
|
112
|
+
else:
|
|
113
|
+
opt_help = opt_descr
|
|
114
|
+
|
|
115
|
+
print(' --%-28s %s' % (opt, opt_help))
|
|
116
|
+
else:
|
|
117
|
+
print(USAGE.format(pytrace=pytrace))
|
|
118
|
+
|
|
119
|
+
for cmd in COMMANDS_ORDER:
|
|
120
|
+
mod = COMMANDS[cmd]
|
|
121
|
+
first_line = mod.ABOUT.splitlines()[0]
|
|
122
|
+
print(" %-18s %s" % (cmd, first_line))
|
|
123
|
+
|
|
124
|
+
if error:
|
|
125
|
+
prefix = "{pytrace} {command}".format(pytrace=pytrace, command=command) if command else pytrace
|
|
126
|
+
print('')
|
|
127
|
+
print("ERROR: {prefix}: {error}".format(prefix=prefix, error=error))
|
|
128
|
+
|
|
129
|
+
sys.exit(1 if error else 0)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
if __name__ == '__main__':
|
|
133
|
+
main()
|
pythonagent/main/wsgi.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from __future__ import unicode_literals
|
|
2
|
+
|
|
3
|
+
from pythonagent.agent.probes.frameworks.wsgi import WSGIMiddleware
|
|
4
|
+
#from pythonagent import config
|
|
5
|
+
#config.WSGI_SCRIPT_ALIAS = input("Enter the absolute path of WSGI application script. (command to get 'readlink -f <script_path.py>') : ")
|
|
6
|
+
application = WSGIMiddleware()
|
pythonagent/main.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
""""
|
|
2
|
+
Local Testing for Python Agent on AWS Lambda
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
python_agent_parent_dir = os.path.abspath(os.path.join(__file__, "../.."))
|
|
9
|
+
sys.path.append(python_agent_parent_dir)
|
|
10
|
+
|
|
11
|
+
from pythonagent.bootstrap.cavagent_lambda_wrapper import handler
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
|
|
16
|
+
event = {"path": "test_local_application"}
|
|
17
|
+
|
|
18
|
+
class Context:
|
|
19
|
+
def __init__(self):
|
|
20
|
+
self.log_stream_name = "test_request_id_localapp"
|
|
21
|
+
self.aws_request_id = "test_request_id_localapp"
|
|
22
|
+
self.function_name = "test_function_localapp"
|
|
23
|
+
|
|
24
|
+
context = Context()
|
|
25
|
+
|
|
26
|
+
response = handler(event, context)
|
|
27
|
+
|
pythonagent/run.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import boto3
|
|
3
|
+
from flask import Flask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def http_callout():
|
|
7
|
+
print("Client Lambda - HTTP Callout Begin")
|
|
8
|
+
x = requests.get('https://www.facebook.com/')
|
|
9
|
+
# x = requests.put('https://httpbin.org/put', data={'key': 'value'})
|
|
10
|
+
# x = requests.post('https://www.w3schools.com/python/demopage.php', data={'key': 'value'})
|
|
11
|
+
# x = requests.delete('https://httpbin.org/delete', data={'key': 'value'})
|
|
12
|
+
print("Client Lambda - HTTP Callout End")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def first():
|
|
16
|
+
print("Client Lambda - First Function")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def second():
|
|
20
|
+
print("Client Lambda - Second Function")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def db_callout():
|
|
24
|
+
print("Client Lambda - DB Callout Begin")
|
|
25
|
+
client = boto3.client('dynamodb')
|
|
26
|
+
print("client METHODS FOR THIS SESSION::", dir(client))
|
|
27
|
+
data = client.scan(TableName='Person')
|
|
28
|
+
item = {
|
|
29
|
+
"id": {"N": "556"},
|
|
30
|
+
"address": {"S": "United States"},
|
|
31
|
+
"firstName": {"S": "John"},
|
|
32
|
+
"lastName": {"S": "Doe"},
|
|
33
|
+
"age": {"N": "30"}
|
|
34
|
+
}
|
|
35
|
+
response = client.put_item(TableName='Person', Item=item)
|
|
36
|
+
print("Client Lambda - DB Call out Begin")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def flask_wsgi():
|
|
40
|
+
app = Flask(__name__)
|
|
41
|
+
|
|
42
|
+
@app.route("/")
|
|
43
|
+
def hello_world():
|
|
44
|
+
return "<p>Hello, World!</p>"
|
|
45
|
+
|
|
46
|
+
app.run(port=6063)
|
pythonagent/sqins.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import sqlite3
|
|
2
|
+
con = sqlite3.connect('checklist.db')
|
|
3
|
+
con.execute("CREATE TABLE checklist(id INTEGER PRIMARY KEY,task VARCHAR(100) NOT NULL,description VARCHAR(200) NOT NULL,status VARCHAR(3) NOT NULL)")
|
|
4
|
+
con.execute("INSERT INTO checklist(id,task,description,status) VALUES (1,'Task number 1', 'This is a description about Task number 1', 'Yes')")
|
|
5
|
+
con.execute("INSERT INTO checklist(id,task,description,status) VALUES (2,'Task number 2', 'This is a description about Task number 2', 'Yes')")
|
|
6
|
+
con.execute("INSERT INTO checklist(id,task,description,status) VALUES (3,'Task number 3', 'This is a description about Task number 3', 'Yes')")
|
|
7
|
+
con.commit()
|
|
8
|
+
|