-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
80bfe90
commit 17e16ed
Showing
13 changed files
with
644 additions
and
45 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import os | ||
from functools import lru_cache | ||
|
||
import yaml | ||
|
||
from cloudshell.recorder.rest.model import RestRequest, RestSession | ||
|
||
|
||
class Configuration(object): | ||
SESSION_KEY = 'Session' | ||
RECORDS_KEY = 'Requests' | ||
|
||
def __init__(self, config_path): | ||
self._config_path = config_path | ||
|
||
@property | ||
@lru_cache() | ||
def _config(self): | ||
with open(self._config_path, 'r') as config: | ||
return yaml.load(config) | ||
|
||
def get_session(self): | ||
return RestSession(**self._config.get(self.SESSION_KEY)) | ||
|
||
def get_requests(self): | ||
table = [] | ||
for record_args in self._config.get(self.RECORDS_KEY): | ||
table.append(RestRequest(**record_args)) | ||
return table |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
-----BEGIN PRIVATE KEY----- | ||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEYq0VRhFTYhdU | ||
s0aCa3R5fooGe5o956zbdx2S6lXnIZIE3ButzzE28VCLoR7qIZb08+1thU6HPpLC | ||
th0fIUQ30+tjmQhK3KPwFXpaJ32svuf15rQ5qXj34Uz3q8SXYhUZQs+zMnOTynee | ||
9EOgdozfLsLn8XJ5iwJseLp5M5WQHMteVoR7bOlzw3Pem39hGMv2p1CCkGZR2LH5 | ||
INEKpOWAx6pR6hhltr7Mu1/pluDJRt6cVliAERYhiatQwI76ZbPY5BJ5yVvcX7Ra | ||
7HlXDCisfHzSHDcohVQc9iSRRQQfUVGuzxWjtTz3cLcHSl5puvE4qmIyCgtI7Jqk | ||
Sz7wSp85AgMBAAECggEBAIFOt8iaKi5NGC+dG4AkYLzepOM/33+DXD3lYIOr6IQX | ||
hp3MkC0Rj8Ytfmtx23kuRMdlFaBXdi129gte/i3RKanYz9T0npEsVoVunvFdr1Jf | ||
ITy4e1K8U/pjTtqFLxy+aEYJx9imD5PwbHMtQpoVdQw/Lfaq9EUzUpU5qQ7E+GW6 | ||
Z6wTO4v8t4IR0+4ETPGAZTqabV3dNrnjaJP30EI9wwk+I0XPeKzGNZQ15FqOp8tR | ||
cS9Eyt2L1r1iWNziP0Lnz7oP0k0BhSgHsZSae7FuXtFrsxmQnggS0MeBdg2kurbk | ||
8ZvcH9RHTH+b+ZZ5XwUCHDhl4Sp5lbxj78rgorNqeAECgYEA80aq3Ox1J5JfZHHf | ||
kZWu/sDjdguNCEEob+A3s2YzBU2QqNsD1jrR5pDI+mXMbpvrdx29luB6CJwbdmWE | ||
P1F0AYB9OT1BDEMlENgckT65ui7eD2a6TMYx0wGU5fys/qKjC3cKXzTghwArMRZf | ||
HPKr/lFTqgG+ClqoNSMKQaYr8PECgYEAzqgrXzvdEGL/H9jMqi1KuQWMLszCIUYp | ||
1iESST78njBcPDJZyRJQ8eVPv06FzgA3Eg/iWrdHxNo8PdiQt9oSJM7dbPOEHyHu | ||
1dc4OOV63b0O4ZIWgPiUeOHwlqv5pRLxDDd/Qa24g86YbdEaZgTc0tpqyS1isDaJ | ||
/ucyGe5xkskCgYBWqUvgm1M4n4nfzDjqMbo/AhOFT6QT1rJC+EqfW769Gt53aF27 | ||
iQSQ7+7IVE847843hp6tCpYuTv3xdURhEfETP+Rb6ZgseBbSI0o563BaBKwSLHQd | ||
OVUyZ5PVQeeWZfVS9jr5o2qAbOz19ZQ4SbI/TFVTcH90TMsy8qKKtFle4QKBgF7n | ||
iiuNIWOSIxnsBWmtrSA1NQCVFh4Ty8jDnVM38uluyhz2/pbBq5y7M5lmpTpKjP/l | ||
fY0tmG8Fzh6U4zkbk7OFsNiFKMrnWXipAu/WK0vDtB7RaTZHcl/lWwjG57nwbfSv | ||
U+jEr/UQHp5oJhht6T+IAPxstGK6WTtPz4lrIItJAoGAJcAuIN4aOinOdC1twzEK | ||
JldVBqf2IFg/D2pSn6h1FZ4uh6gs9yIJTniBBPUHfqdeg+bez+XxXQfsuSJsAs6+ | ||
sDUzdzzQ/PsL5KZiR/XVTWditYBuMofKMlSLf7nsF/kgAolmlzqc02b0bBipNU7D | ||
lSTW5FLznGl8c2wXdffcbzc= | ||
-----END PRIVATE KEY----- | ||
-----BEGIN CERTIFICATE----- | ||
MIIDNDCCAhwCCQCj4EmTXe2D0zANBgkqhkiG9w0BAQsFADBcMQswCQYDVQQGEwJV | ||
QTENMAsGA1UECAwES2lldjENMAsGA1UEBwwES2lldjEOMAwGA1UECgwFUXVhbGkx | ||
CzAJBgNVBAsMAklUMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTkxMDE4MTQyODQ3 | ||
WhcNMjAxMDE3MTQyODQ3WjBcMQswCQYDVQQGEwJVQTENMAsGA1UECAwES2lldjEN | ||
MAsGA1UEBwwES2lldjEOMAwGA1UECgwFUXVhbGkxCzAJBgNVBAsMAklUMRIwEAYD | ||
VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDE | ||
Yq0VRhFTYhdUs0aCa3R5fooGe5o956zbdx2S6lXnIZIE3ButzzE28VCLoR7qIZb0 | ||
8+1thU6HPpLCth0fIUQ30+tjmQhK3KPwFXpaJ32svuf15rQ5qXj34Uz3q8SXYhUZ | ||
Qs+zMnOTynee9EOgdozfLsLn8XJ5iwJseLp5M5WQHMteVoR7bOlzw3Pem39hGMv2 | ||
p1CCkGZR2LH5INEKpOWAx6pR6hhltr7Mu1/pluDJRt6cVliAERYhiatQwI76ZbPY | ||
5BJ5yVvcX7Ra7HlXDCisfHzSHDcohVQc9iSRRQQfUVGuzxWjtTz3cLcHSl5puvE4 | ||
qmIyCgtI7JqkSz7wSp85AgMBAAEwDQYJKoZIhvcNAQELBQADggEBALOeVzCPqxYo | ||
JfVoVbZ842QJyPrcVn/Y+EThz2BoCpmDoca1w/EF9KuhDtdV2iFZRHKnep+w5VPJ | ||
p8K+UH50YEkQtCHM8Budx2BCuGiInCF6zX3EC0LsmB4pC1Q38UKsycNnRr1p20nz | ||
36DBvSLdECVUiern8EktlKzYXsOX/FgRTFoz6t8iQwHaf11XSccYyeYV4PCInck4 | ||
+YaYYXylgUUtAjGD8rRmlfEM1NiIL1RYivOGsCnRJHxHnIysdPgw7gOoQ2kD5xmZ | ||
FX0EWTO/CldSL92+b2HqlZmg1yCdfuCpZvc7guJLaaQy3lwFuy0Z0vV+tlm/LvBm | ||
89boXvLV61A= | ||
-----END CERTIFICATE----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from cloudshell.recorder.rest.configuration import Configuration | ||
from cloudshell.recorder.rest.rest_recorder import RestRecorder | ||
|
||
if __name__ == '__main__': | ||
record_table = "request_table_visionedge.yaml" | ||
base_url = "https://192.168.51.68:8000/api" | ||
|
||
conf = Configuration(record_table) | ||
|
||
recorder = RestRecorder(base_url) | ||
recorder.initialize(conf.get_session()) | ||
recorder.record(conf.get_requests()) | ||
recorder.save('saved_table.yaml') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
class RestSession(object): | ||
def __init__(self, username=None, password=None, token=None, headers=None): | ||
self.username = username | ||
self.password = password | ||
self.token = token | ||
self.headers = headers | ||
|
||
|
||
class RestRequest(object): | ||
def __init__(self, uri, method='GET', data=None, headers=None): | ||
self.method = method | ||
self.uri = uri | ||
self.data = data | ||
self.headers = headers | ||
|
||
def __hash__(self): | ||
return hash(self.method) | hash(self.uri) | hash(self.data) | ||
|
||
def __eq__(self, other): | ||
""" | ||
:param RestRequest other: | ||
""" | ||
return self.uri == other.uri and self.method == other.method and self.data == other.data | ||
|
||
|
||
class RestResponse(object): | ||
def __init__(self, status_code, headers, content): | ||
self.status_code = status_code | ||
self.headers = headers | ||
self.content = content |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import os | ||
from functools import lru_cache | ||
from http.server import BaseHTTPRequestHandler | ||
from urllib.error import HTTPError | ||
from urllib.parse import urlparse | ||
import vcr | ||
import urllib3 | ||
|
||
|
||
|
||
class RestSimHTTPRequestHandler(BaseHTTPRequestHandler): | ||
URL = None | ||
RECORD_PATH = None | ||
# CASSETTE_FILE = None | ||
CASSETTE_NAME_TEMPLATE = "{scheme}_{host}_{port}.yaml" | ||
RECORD_MODE = False | ||
CONN_CONT_MANAGER = None | ||
VCR_CONT_MANAGER = None | ||
|
||
# @property | ||
# def _dst_url(self): | ||
# return "{}{}".format(self.URL, self.path) | ||
|
||
@property | ||
@lru_cache() | ||
def _dst_url_obj(self): | ||
return urlparse(self.URL) | ||
|
||
@property | ||
def _dst_scheme(self): | ||
return self._dst_url_obj.scheme | ||
|
||
@property | ||
def _dst_hostname(self): | ||
return self._dst_url_obj.hostname | ||
|
||
@property | ||
def _dst_port(self): | ||
return self._dst_url_obj.port | ||
|
||
def _cassette_name(self): | ||
if not self._dst_port and self._dst_scheme.lower() == 'http': | ||
port = '80' | ||
elif not self._dst_port: | ||
port = '443' | ||
else: | ||
port = self._dst_port | ||
return self.CASSETTE_NAME_TEMPLATE.format(scheme=self._dst_scheme, host=self._dst_hostname, port=port) | ||
|
||
@lru_cache() | ||
def _cassette_path(self): | ||
if self.RECORD_PATH and os.path.isfile(self.RECORD_PATH): | ||
return self.RECORD_PATH | ||
elif self.RECORD_PATH and os.path.isdir(self.RECORD_PATH): | ||
return os.path.join(self.RECORD_PATH, self._cassette_name()) | ||
else: | ||
return self._cassette_name() | ||
|
||
def _assign_headers(self, headers): | ||
for key, val in headers.items(): | ||
self.send_header(key, val) | ||
self.end_headers() | ||
|
||
def _send_response(self, code, headers, data): | ||
self.send_response(code) | ||
self._assign_headers(headers) | ||
self.wfile.write(data) | ||
|
||
def _handle_request(self, method, handle_data=False): | ||
# if self.RECORD_MODE: | ||
# vcr_cass_man = vcr.use_cassette(self._cassette_path(), record_mode='new_episodes', | ||
# match_on=('method', 'path', 'query')) | ||
# else: | ||
# vcr_cass_man = vcr.use_cassette(self._cassette_path(), match_on=('method', 'path', 'query')) | ||
with self.VCR_CONT_MANAGER as cass: | ||
if handle_data: | ||
content_len = int(self.headers.get('Content-Length', 0)) | ||
data = self.rfile.read(content_len) | ||
else: | ||
data = None | ||
try: | ||
with urllib3.connectionpool.connection_from_url(self.URL, cert_reqs='CERT_NONE') as conn: | ||
resp = conn.urlopen(method=method, url=self.path, headers=self.headers, body=data) | ||
self._send_response(resp.status, resp.headers, resp.data) | ||
except HTTPError as e: | ||
self._send_response(e.code, e.headers, e.msg.encode()) | ||
|
||
def do_GET(self): | ||
method = "GET" | ||
self._handle_request(method) | ||
|
||
def do_POST(self): | ||
method = "POST" | ||
self._handle_request(method, True) | ||
|
||
def do_PUT(self): | ||
method = "PUT" | ||
self._handle_request(method, True) | ||
|
||
def do_PATCH(self): | ||
method = "PATCH" | ||
self._handle_request(method, True) | ||
|
||
def do_DELETE(self): | ||
method = "DELETE" | ||
self._handle_request(method) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
Session: | ||
username: admin | ||
password: admin | ||
token: | ||
headers: | ||
Accept: '*/*' | ||
Authorization: MachineName=;Token= | ||
ClientTimeZoneId: UTC | ||
Content-Type: text/xml | ||
DateTimeFormat: MM/dd/yyyy HH:mm | ||
Requests: | ||
- data: <Logon><username>admin</username><password>admin</password><domainName>Global</domainName></Logon> | ||
method: post | ||
uri: /ResourceManagerApiService/Logon | ||
- data: <GetServerDateAndTime /> | ||
method: post | ||
uri: /ResourceManagerApiService/GetServerDateAndTime |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
Session: | ||
username: admin | ||
password: admin | ||
Requests: | ||
- uri: /api/ports | ||
- uri: /api/cte_ports | ||
- uri: /api/cte_filters |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import logging | ||
import os | ||
import ssl | ||
import sys | ||
import urllib | ||
from http.server import HTTPServer | ||
from urllib.parse import urlparse | ||
|
||
import click | ||
import pkg_resources | ||
import urllib3 | ||
import vcr | ||
|
||
from cloudshell.recorder.rest.request_handler import RestSimHTTPRequestHandler | ||
|
||
urllib3.disable_warnings() | ||
|
||
CASSETTE_NAME_TEMPLATE = "{scheme}_{host}_{port}.yaml" | ||
MATCH_ON = ('method', 'path', 'query') | ||
|
||
|
||
def _enable_debug(): | ||
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, | ||
format="%(asctime)s [%(levelname)s]: %(name)s %(module)s - %(funcName)-20s %(message)s") | ||
|
||
|
||
@click.group(invoke_without_command=True) | ||
@click.option(u'--version', u'-v', is_flag=True, default=False, help='Package version.') | ||
@click.pass_context | ||
def rest_cli(ctx, version): | ||
"""For more information on a specific command, type migration_tool COMMAND --help""" | ||
if version: | ||
version = pkg_resources.get_distribution("cloudshell-recording").version | ||
click.echo('Version: {}'.format(version)) | ||
ctx.exit(0) | ||
else: | ||
if not ctx.invoked_subcommand: | ||
click.echo(ctx.get_help()) | ||
|
||
|
||
@rest_cli.command() | ||
@click.option("--host", "-h", default="localhost", | ||
help="Listen host. Default: localhost") | ||
@click.option("--port", "-p", default=None, | ||
help="Listen port. Default: dst url port") | ||
@click.option("--scheme", "-s", default=None, help="Listen scheme, http or https, Default: dst url scheme.") | ||
@click.option("--file-path", "-f", default=None, help="Record path. Default: current path.") | ||
@click.option("--debug", "-d", is_flag=True, default=False, help="Enable debug.") | ||
@click.option("--record", "-r", "record_mode", is_flag=True, default=False, help="Enable record mode.") | ||
@click.argument(u'url', type=str, default=None, required=True) | ||
def record(host, port, scheme, file_path, debug, record_mode, url): | ||
if debug: | ||
_enable_debug() | ||
|
||
RestSimHTTPRequestHandler.URL = url | ||
RestSimHTTPRequestHandler.RECORD_PATH = file_path | ||
RestSimHTTPRequestHandler.RECORD_MODE = False | ||
|
||
if record_mode: | ||
vcr_cass_man = vcr.use_cassette(_cassette_path(url, file_path), record_mode='new_episodes', | ||
match_on=MATCH_ON) | ||
else: | ||
vcr_cass_man = vcr.use_cassette(_cassette_path(url, file_path), match_on=MATCH_ON) | ||
|
||
RestSimHTTPRequestHandler.VCR_CONT_MANAGER = vcr_cass_man | ||
|
||
url_obj = urllib.parse.urlparse(url) | ||
if not port and not url_obj.port: | ||
if scheme == "http" or url_obj.scheme == "http": | ||
port = 80 | ||
else: | ||
port = 443 | ||
else: | ||
port = port or url_obj.port | ||
server = HTTPServer((host, port), RestSimHTTPRequestHandler) | ||
if (scheme and scheme == "https") or url_obj.scheme == "https": | ||
server.socket = ssl.wrap_socket(server.socket, server_side=True, | ||
certfile=os.path.join(os.path.dirname(__file__), 'default.pem')) | ||
server.serve_forever() | ||
|
||
|
||
def _cassette_name(url): | ||
url_obj = urllib.parse.urlparse(url) | ||
if not url_obj.port and url_obj.scheme.lower() == 'http': | ||
port = '80' | ||
elif not url_obj.port: | ||
port = '443' | ||
else: | ||
port = url_obj.port | ||
return CASSETTE_NAME_TEMPLATE.format(scheme=url_obj.scheme, host=url_obj.hostname, port=port) | ||
|
||
|
||
def _cassette_path(url, path): | ||
if path and os.path.isfile(path): | ||
return path | ||
elif path and os.path.isdir(path): | ||
return os.path.join(path, _cassette_name(url)) | ||
else: | ||
return _cassette_name(url) | ||
|
||
|
||
@rest_cli.command() | ||
def simulate(): | ||
pass | ||
|
||
|
||
if __name__ == '__main__': | ||
rest_cli() |
Oops, something went wrong.