diff --git a/python/avi/migrationtools/nsxt_converter/__init__.py b/python/avi/migrationtools/nsxt_converter/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/python/avi/migrationtools/nsxt_converter/base_client.py b/python/avi/migrationtools/nsxt_converter/base_client.py new file mode 100755 index 0000000000..44ba216a52 --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/base_client.py @@ -0,0 +1,288 @@ +import base64 + +import json +import re +import requests +import logging +from requests.packages.urllib3.exceptions import InsecureRequestWarning +from requests.adapters import HTTPAdapter +from requests.packages.urllib3.util.retry import Retry + +LOG = logging.getLogger(__name__) + +requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + + +class DetailedHttpError(requests.exceptions.HTTPError): + def __init__(self, response): + self.err_code = 0 + # MC concatenates messages with newlines + reason = response.text.replace("\n", "") + try: + # Handle both NSX-T and NSX-V error messages + # extract brief string reason if present + reason_json = response.json() + if 'error_message' in reason_json: + reason = reason_json['error_message'] + elif 'details' in reason_json: + reason = reason_json['details'] + if 'error_code' in reason_json: + self.err_code = reason_json['error_code'] + elif 'errorCode' in reason_json: + self.err_code = reason_json['errorCode'] + except Exception: + pass + + http_error_msg = u'%s: %s for url: %s' % (response.status_code, reason, response.url) + super(DetailedHttpError, self).__init__(http_error_msg, response=response) + + +class NSXClient(object): + """Base NSX REST client""" + + ALLOWED_GET_STATUS = [requests.codes.OK] + ALLOWED_POST_STATUS = [requests.codes.OK, + requests.codes.CREATED, + requests.codes.ACCEPTED, + requests.codes.NO_CONTENT] + ALLOWED_PUT_STATUS = [requests.codes.OK, + requests.codes.CREATED, + requests.codes.ACCEPTED, + requests.codes.NO_CONTENT] + ALLOWED_DEL_STATUS = [requests.codes.OK, + requests.codes.ACCEPTED, + requests.codes.NO_CONTENT, + requests.codes.NOT_FOUND] + + def __init__(self, host, prefix, username=None, password=None, auth_token=None, + timeout=720, retries=5, logger=None): + self.host = host + self.username = username + self.password = password + self.auth_token = auth_token + self.timeout = timeout + self.retries = retries + self.version = None + self.content_type = "application/json" + self.accept_type = "application/json" + self.verify = False + if "localhost" in self.host: + self.secure = False + else: + self.secure = True + self.interface = "json" + self.logger = LOG if logger is None else logger + self.prefix = prefix + self._session_hdrs = None + self.session = None + self.set_session_headers() + + def set_content_type(self, content_type): + self.content_type = content_type + + def get_content_type(self): + return self.content_type + + def set_accept_type(self, accept_type): + self.accept_type = accept_type + + def get_accept_type(self): + return self.accept_type + + def customize_session(self): + if self.session: + return self.session + + session = requests.Session() + retry = Retry(total=self.retries, + read=self.retries, + connect=self.retries) + adapter = HTTPAdapter(max_retries=retry) + session.mount('http://', adapter) + session.mount('https://', adapter) + + session.headers.update(self._session_hdrs) + + self.session = session + return self.session + + def _get_url(self, endpoint): + http_type = 'https' if self.secure else 'http' + url = '%s/%s/%s' % (self.host, self.prefix, endpoint) + # remove possible double/triple slashes + url = re.sub('/+', '/', url) + url = '%s://%s' % (http_type, url) + return url + + def is_localhost(self): + return bool("localhost" in self.host) + + def set_session_headers(self, content=None, accept=None): + content_type = self.content_type if content is None else content + accept_type = self.accept_type if accept is None else accept + headers = {} + if self.username is not None and self.password is not None: + auth_cred = self.username + ":" + self.password + auth = base64.b64encode(auth_cred.encode()) + headers['Authorization'] = "Basic %s" % auth.decode() + + if self.auth_token is not None: + headers['Authorization'] = "AUTHTOKEN %s" % self.auth_token + + headers['Content-Type'] = content_type + headers['Accept'] = accept_type + # In case manager API forces to PUT policy created object. + headers['X-Allow-Overwrite'] = 'true' + if self.username is None: + # This header is needed for communication over http + # Value is set to be same with as policy, to avoid identity conflict + headers['X-NSX-Username'] = 'admin' + + self._session_hdrs = headers + if self.session: + self.session.headers.update(self._session_hdrs) + + def add_session_header(self, key, value): + if self.session: + self.session.headers[key] = value + else: + self._session_hdrs[key] = value + + def remove_session_header(self, key): + if self.session: + if key in self.session.headers: + del self.session.headers[key] + elif key in self._session_hdrs: + del self._session_hdrs[key] + + def _is_sensitive(self, url, data=None): + url_keywords = ['certificate'] + for keyword in url_keywords: + if keyword in url: + return True + + if data and 'password' in str(data): + return True + + return False + + def _log_api_call(self, method, url, data=None, params=None, headers=None): + # Avoid exposing sensitive data - data for certain URLs should + # not be logged + + sensitive = self._is_sensitive(url, data) + if data and sensitive: + data = "" + + self.logger.debug("API tracker: REQUEST method=%s, url=%s, " + "non-session-headers=%s, params=%s, data=%s", + method, url, str(headers), str(params), str(data)) + + def _mask_psk(self, resp_text): + masked_text = re.sub(r"\"psk\"+\s*:\s*\"(.*?)\"", "\"psk\":\"****\"", resp_text) + return masked_text + + def _log_api_call_response(self, response): + if response: + resp_text = response.text + if resp_text and len(resp_text) > 1000: + resp_text = resp_text[:1000] + " ..." + if resp_text and "psk" in resp_text: + resp_text = self._mask_psk(resp_text) + + self.logger.debug("API tracker: RESPONSE status=%s, text=%s", + response.status_code, resp_text) + + def _session_call(self, session, method, url, data=None, params=None, non_session_headers=None): + + method = method.lower() + response = None + if data: + response = getattr(session, method)(url, headers=non_session_headers, + verify=self.verify, + data=data, + params=params, + timeout=self.timeout) + else: + response = getattr(session, method)(url, headers=non_session_headers, + verify=self.verify, + params=params, + timeout=self.timeout) + + if response.status_code == requests.codes.TOO_MANY_REQUESTS: + raise Exception() + + return response + + def _rest_call(self, method, endpoint, data, allowed_statuses, raise_ex=True, + log_on_fail=True, return_failure=False, params=None, headers=None): + session = self.customize_session() + url = self._get_url(endpoint) + self._log_api_call(method, url, data, params, headers) + response = self._session_call(session, method, url, data, params, headers) + self._log_api_call_response(response) + if response.status_code in allowed_statuses: + return response + else: + if log_on_fail: + self.logger.error("Failed to %s %s with status: %s and reason: %s", + method, url, response.status_code, response.text) + if response.status_code == requests.codes.FORBIDDEN: + self.logger.error("Failed to %s %s with status: %s and reason: %s", + method, url, response.status_code, response.text) + if self.auth_token: + msg = "Authtoken may be invalid/expired. Please generate a new one "\ + "and continue with migration" + print(msg) + if self.username is not None and self.password is not None: + msg = "Invalid username/password used for migration. Please check " \ + "and continue with migration" + print(msg) + if raise_ex: + raise DetailedHttpError(response) + if return_failure: + return response + + def get(self, endpoint, params=None, allowed_status=None, + return_failure=False, non_session_headers=None): + """ + Basic query method for json API request + """ + allowed_get_status = (allowed_status if allowed_status else + self.ALLOWED_GET_STATUS) + return self._rest_call('GET', endpoint, data=None, + allowed_statuses=allowed_get_status, + raise_ex=False, + return_failure=return_failure, + params=params, headers=non_session_headers) + + def put(self, endpoint, body=None, params=None, non_session_headers=None): + """ + Basic put API method on endpoint + """ + put_data = body + if self.content_type == "application/json": + put_data = json.dumps(body) + return self._rest_call('PUT', endpoint, data=put_data, + allowed_statuses=self.ALLOWED_PUT_STATUS, + params=params, headers=non_session_headers) + + def delete(self, endpoint, params=None, log_on_fail=True, non_session_headers=None): + """ + Basic delete API method on endpoint + """ + return self._rest_call('DELETE', endpoint, data=None, + allowed_statuses=self.ALLOWED_DEL_STATUS, + log_on_fail=log_on_fail, params=params, headers=non_session_headers) + + def post(self, endpoint, body=None, raise_ex=True, params=None, non_session_headers=None): + """ + Basic post API method on endpoint + """ + post_data = body + if self.content_type == "application/json": + post_data = json.dumps(body) + return self._rest_call('POST', endpoint, data=post_data, + allowed_statuses=self.ALLOWED_POST_STATUS, + raise_ex=raise_ex, return_failure=(not raise_ex), + params=params, headers=non_session_headers) diff --git a/python/avi/migrationtools/nsxt_converter/conversion_util.py b/python/avi/migrationtools/nsxt_converter/conversion_util.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/python/avi/migrationtools/nsxt_converter/monitor_converter.py b/python/avi/migrationtools/nsxt_converter/monitor_converter.py new file mode 100644 index 0000000000..bcfab16f46 --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/monitor_converter.py @@ -0,0 +1,68 @@ +import com.vmware.nsx_policy.model_client as model_client + +def get_alb_response_codes(response_codes): + if not response_codes: + return None + HttpResponseCode = model_client.ALBHealthMonitorHttp + codes = list() + for code in response_codes: + if code<200: + if HttpResponseCode.HTTP_RESPONSE_CODE_1XX not in codes: + codes.append(HttpResponseCode.HTTP_RESPONSE_CODE_1XX) + elif code>199 and code<300: + if HttpResponseCode.HTTP_RESPONSE_CODE_2XX not in codes: + codes.append(HttpResponseCode.HTTP_RESPONSE_CODE_2XX) + elif code>299 and code<400: + if HttpResponseCode.HTTP_RESPONSE_CODE_3XX not in codes: + codes.append(HttpResponseCode.HTTP_RESPONSE_CODE_3XX) + elif code>399 and code<500: + if HttpResponseCode.HTTP_RESPONSE_CODE_4XX not in codes: + codes.append(HttpResponseCode.HTTP_RESPONSE_CODE_4XX) + elif code>499 and code<600: + if HttpResponseCode.HTTP_RESPONSE_CODE_5XX not in codes: + codes.append(HttpResponseCode.HTTP_RESPONSE_CODE_5XX) + return codes + + +def update_alb_type(lb_hm, alb_hm): + + if lb_hm['resource_type'] == 'LBHttpMonitorProfile': + alb_hm['type'] = 'HEALTH_MONITOR_HTTP' + alb_hm['http_monitor'] = dict( + http_request=lb_hm['request_url'], + http_request_body=lb_hm.get('request_body'), + http_response=lb_hm.get('response_body'), + http_response_code=get_alb_response_codes(lb_hm['response_status_codes']), + ) + elif lb_hm['resource_type'] == 'LBHttpsMonitorProfile': + alb_hm['type'] = 'HEALTH_MONITOR_HTTPS' + alb_hm['https_monitor'] = dict( + http_request=lb_hm['request_url'], + http_request_body=lb_hm.get('request_body'), + http_response=lb_hm.get('response_body'), + http_response_code=get_alb_response_codes(lb_hm['response_status_codes']), + ) + elif lb_hm['resource_type'] == 'LBIcmpMonitorProfile': + alb_hm['type'] = 'HEALTH_MONITOR_PING' + elif lb_hm['resource_type'] == 'LBTcpMonitorProfile': + alb_hm['type'] = 'HEALTH_MONITOR_TCP' + elif lb_hm['resource_type'] == 'LbUdpMonitorProfile': + alb_hm['type'] = 'HEALTH_MONITOR_UDP' + + +def convert(alb_config, nsx_lb_config): + alb_config['HealthMonitor'] = list() + + for lb_hm in nsx_lb_config['LbMonitorProfiles']: + if lb_hm['resource_type'] == 'LBPassiveMonitorProfile': + continue + alb_hm = dict( + name=lb_hm['display_name'], + failed_checks=lb_hm['fall_count'], + receive_timeout=lb_hm['timeout'], + send_interval=lb_hm['interval'], + monitor_port=lb_hm.get('monitor_port', None), + ) + update_alb_type(lb_hm, alb_hm) + + alb_config['HealthMonitor'].append(alb_hm) diff --git a/python/avi/migrationtools/nsxt_converter/nsxt_client.py b/python/avi/migrationtools/nsxt_converter/nsxt_client.py new file mode 100644 index 0000000000..486ab5b58f --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/nsxt_client.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python + +import requests + +from com.vmware import nsx_client +from com.vmware import nsx_policy_client +from vmware.vapi.bindings.stub import ApiClient +from vmware.vapi.bindings.stub import StubFactory +from vmware.vapi.lib import connect +from vmware.vapi.security.user_password import \ + create_user_password_security_context +from vmware.vapi.stdlib.client.factories import StubConfigurationFactory + +BASIC_AUTH = 1 +SESSION_AUTH = 2 + + +def get_basic_auth_stub_config(user, password, nsx_host, tcp_port=443): + """ + Create a stub configuration that uses HTTP basic authentication. + """ + session = requests.session() + + # Since the NSX manager default certificate is self-signed, + # we disable verification. This is dangerous and real code + # should verify that it is talking to a valid server. + session.verify = False + requests.packages.urllib3.disable_warnings() + + nsx_url = 'https://%s:%s' % (nsx_host, tcp_port) + connector = connect.get_requests_connector( + session=session, msg_protocol='rest', url=nsx_url) + stub_config = StubConfigurationFactory.new_runtime_configuration( + connector, response_extractor=True) + security_context = create_user_password_security_context( + user, password) + connector.set_security_context(security_context) + return stub_config + + +def get_basic_auth_api_client(user, password, nsx_host, tcp_port=443): + stub_config = get_basic_auth_stub_config( + user, password, nsx_host, tcp_port) + stub_factory = nsx_client.StubFactory(stub_config) + return ApiClient(stub_factory) + + +def get_session_auth_stub_config(user, password, nsx_host, tcp_port=443): + """ + Create a stub configuration that uses session-based authentication. + Session authentication is more efficient, since the server only + needs to perform authentication of the username/password one time. + """ + session = requests.session() + + # Since the NSX manager default certificate is self-signed, + # we disable verification. This is dangerous and real code + # should verify that it is talking to a valid server. + session.verify = False + requests.packages.urllib3.disable_warnings() + nsx_url = 'https://%s:%s' % (nsx_host, tcp_port) + resp = session.post(nsx_url + "/api/session/create", + data={"j_username": user, "j_password": password}) + if resp.status_code != requests.codes.ok: + resp.raise_for_status() + + # Set the Cookie and X-XSRF-TOKEN headers + session.headers["Cookie"] = resp.headers.get("Set-Cookie") + session.headers["X-XSRF-TOKEN"] = resp.headers.get("X-XSRF-TOKEN") + + connector = connect.get_requests_connector( + session=session, msg_protocol='rest', url=nsx_url) + stub_config = StubConfigurationFactory.new_runtime_configuration( + connector, response_extractor=True) + return stub_config + + +def get_session_auth_api_client(user, password, nsx_host, tcp_port=443): + stub_config = get_session_auth_stub_config( + user, password, nsx_host, tcp_port) + stub_factory = nsx_client.StubFactory(stub_config) + return ApiClient(stub_factory) + + +def create_api_client(stub_factory_class, user, password, nsx_host, + tcp_port=443, auth_type=BASIC_AUTH): + if auth_type == BASIC_AUTH: + stub_config = get_basic_auth_stub_config( + user, password, nsx_host, tcp_port) + elif auth_type == SESSION_AUTH: + stub_config = get_session_auth_stub_config( + user, password, nsx_host, tcp_port) + stub_factory = stub_factory_class.StubFactory(stub_config) + return ApiClient(stub_factory) + + +def create_nsx_api_client(user, password, nsx_host, tcp_port=443, + auth_type=BASIC_AUTH): + return create_api_client(nsx_client, user, password, nsx_host, + tcp_port, auth_type) + + +def create_nsx_policy_api_client(user, password, nsx_host, tcp_port=443, + auth_type=BASIC_AUTH): + return create_api_client(nsx_policy_client, user, password, nsx_host, + tcp_port, auth_type) diff --git a/python/avi/migrationtools/nsxt_converter/nsxt_config_converter.py b/python/avi/migrationtools/nsxt_converter/nsxt_config_converter.py new file mode 100644 index 0000000000..97fb29da1c --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/nsxt_config_converter.py @@ -0,0 +1,48 @@ + +import sys + +from avi.migrationtools.ace_converter import pool_converter +from avi.migrationtools.nsxt_converter import nsxt_client as nsx_client_util, pools_converter, vs_converter +from avi.migrationtools.nsxt_converter import monitor_converter +from avi.migrationtools.nsxt_converter import profiles_converter +from vmware.vapi.bindings.struct import PrettyPrinter +from com.vmware.vapi.std.errors_client import NotFound +from com.vmware.nsx.loadbalancer_client import Pools +import com.vmware.nsx_policy.infra_client as infra_client +import com.vmware.nsx_policy.model_client as model_client +import random +from com.vmware.vapi.std.errors_client import Error +from avi.migrationtools.nsxt_converter.nsxt_util import NSXUtil +import os +import json + + +def convert(nsx_ip, nsx_un, nsx_pw, nsx_port, output_dir): + nsx_util = NSXUtil(nsx_un, nsx_pw, nsx_ip, nsx_port) + nsx_lb_config = nsx_util.get_nsx_config() + input_path = output_dir + os.path.sep + nsx_ip + os.path.sep + "input" + if not os.path.exists(input_path): + os.makedirs(input_path) + input_config = input_path + os.path.sep + "config.json" + with open(input_config, "w", encoding='utf-8') as text_file: + json.dump(nsx_lb_config, text_file, indent=4) + + + alb_config = dict() # Result Config + + monitor_converter.convert(alb_config, nsx_lb_config) + profiles_converter.convert(alb_config, nsx_lb_config) + pools_converter.convert(alb_config, nsx_lb_config) + vs_converter.convert(alb_config,nsx_lb_config) + + output_path = output_dir + os.path.sep + nsx_ip + os.path.sep + "output" + print(output_path) + if not os.path.exists(output_path): + os.makedirs(output_path) + output_config = output_path + os.path.sep + "avi_config.json" + with open(output_config, "w", encoding='utf-8') as text_file: + json.dump(alb_config, text_file, indent=4) + + + pp = PrettyPrinter() + pp.pprint(alb_config) \ No newline at end of file diff --git a/python/avi/migrationtools/nsxt_converter/nsxt_converter.py b/python/avi/migrationtools/nsxt_converter/nsxt_converter.py new file mode 100644 index 0000000000..f5e9d2246f --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/nsxt_converter.py @@ -0,0 +1,39 @@ +# !/usr/bin/env python3 + +from avi.migrationtools.nsxt_converter import nsxt_config_converter +import argparse + + +def conver_lb_config(args): + output_file_path = args.output_file_path if args.output_file_path else 'output' + nsxt_config_converter.convert(args.nsxt_ip, args.nsxt_user, args.nsxt_passord, args.nsxt_port, output_file_path) + + + + +if __name__ == "__main__": + + HELP_STR = """ + Usage: + python nsxt_converter.py -n 192.168.100.101 -u admin -p password + """ + + parser = argparse.ArgumentParser( + formatter_class=argparse.RawTextHelpFormatter, + description=HELP_STR) + + parser.add_argument('-n', '--nsxt_ip', required=True, + help='Ip of NSXT') + parser.add_argument('-u', '--nsxt_user', required=True, + help='NSX-T User name') + parser.add_argument('-p', '--nsxt_passord', required=True, + help='NSX-T Password') + parser.add_argument('-port', '--nsxt_port', default=443, + help='NSX-T Port') + parser.add_argument('-o', '--output_file_path', + help='Folder path for output files to be created in', + ) + + args = parser.parse_args() + conver_lb_config(args) + diff --git a/python/avi/migrationtools/nsxt_converter/nsxt_util.py b/python/avi/migrationtools/nsxt_converter/nsxt_util.py new file mode 100644 index 0000000000..b0c4fd0e2c --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/nsxt_util.py @@ -0,0 +1,25 @@ + +from avi.migrationtools.nsxt_converter import nsxt_client as nsx_client_util + +class NSXUtil(): + + nsx_api_client = None + + def __init__(self, nsx_un, nsx_pw, nsx_ip, nsx_port): + self.nsx_api_client = nsx_client_util.create_nsx_policy_api_client( + nsx_un, nsx_pw, nsx_ip, nsx_port, auth_type=nsx_client_util.SESSION_AUTH) + + def get_nsx_config(self): + nsx_lb_config = dict() + nsx_lb_config["LBServices"] = self.nsx_api_client.infra.LbServices.list().to_dict().get("results", []) + nsx_lb_config["LbMonitorProfiles"] = self.nsx_api_client.infra.LbMonitorProfiles.list().to_dict().get("results", []) + nsx_lb_config["LbPools"] = self.nsx_api_client.infra.LbPools.list().to_dict().get("results", []) + nsx_lb_config["LbAppProfiles"] = self.nsx_api_client.infra.LbAppProfiles.list().to_dict().get("results", []) + nsx_lb_config["LBVirtualServers"] = self.nsx_api_client.infra.LbVirtualServers.list().to_dict().get("results", []) + + return nsx_lb_config + +if __name__ == "__main__": + nsx_util = NSXUtil('admin', 'Admin!23Admin', '10.168.204.70', '443') + nsx_lb_config = nsx_util.get_nsx_config() + print(nsx_lb_config) \ No newline at end of file diff --git a/python/avi/migrationtools/nsxt_converter/pools_converter.py b/python/avi/migrationtools/nsxt_converter/pools_converter.py new file mode 100644 index 0000000000..abcd503bb7 --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/pools_converter.py @@ -0,0 +1,40 @@ +from avi.migrationtools.nsxt_converter import nsxt_client as nsx_client_util, profiles_converter +def update_alb_type(lb_pl, alb_pl): + if lb_pl['algorithm']=='ROUND_ROBIN': + alb_pl['lb_algorithm'] = 'LB_ALGORITHM_ROUND_ROBIN' + elif lb_pl['algorithm']=='LEAST_CONNECTION': + alb_pl['lb_algorithm'] = 'LB_ALGORITHM_LEAST_CONNECTION' + elif lb_pl['algorithm']== 'IP_HASH': + alb_pl['lb_algorithm'] = 'LB_ALGORITHM_CONSISTENT_HASH_SOURCE_IP_ADDRESS' + alb_pl['min_servers_up']=lb_pl['min_active_members'] + alb_pl['max_concurrent_connections']=lb_pl.get('max_concurrent_connections_per_server') + alb_pl['health_monitor_refs']=lb_pl.get('active_monitor_paths') + alb_pl['servers'] = dict( + ip=dict( + + )) + + for member in lb_pl['members']: + alb_pl['servers']['enabled']=member['admin_state'] + alb_pl['servers']['ip']['addr']=member['ip_address'] + alb_pl['servers']['port']=member['port'] + alb_pl['servers']['ratio']=member['weight'] + alb_pl['servers']['description']=member['display_name'] + + + + alb_pl['ConnPoolProperties']=dict( + upstream_connpool_server_max_cache=lb_pl['tcp_multiplexing_number'] + + ) + + + +def convert(alb_config, nsx_lb_config): + alb_config['Pool'] = list() + for lb_pl in nsx_lb_config['LbPools']: + alb_pl=dict( + name=lb_pl['display_name'] + ) + update_alb_type(lb_pl, alb_pl) + alb_config['Pool'].append(alb_pl) diff --git a/python/avi/migrationtools/nsxt_converter/profiles_converter.py b/python/avi/migrationtools/nsxt_converter/profiles_converter.py new file mode 100644 index 0000000000..f2da092d27 --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/profiles_converter.py @@ -0,0 +1,40 @@ +from avi.migrationtools.nsxt_converter import nsxt_client as nsx_client_util +def update_alb_type(lb_pr, alb_pr): + if lb_pr['resource_type'] == 'LBHttpProfile': + alb_pr['type'] = 'APPLICATION_PROFILE_TYPE_HTTP' + + alb_pr['http_profile'] = dict( + xff_enabled=lb_pr.get('xForwardedFor'), + http_to_https=lb_pr.get('httpRedirectToHttps'), + keepalive_timeout=lb_pr.get('idle_timeout'), + client_max_header_size=lb_pr['request_header_size'], + client_max_body_size=lb_pr.get('requestBodySize') + ) + elif lb_pr['resource_type'] == 'LBFastTcpProfile': + alb_pr['profile']=dict( + type = 'APPLICATION_PROFILE_TYPE_TCP', + tcp_fast_path_profile=dict( + session_idle_timeout=lb_pr['idle_timeout']) + ) + + elif lb_pr['resource_type'] == 'LBFastUdpProfile': + alb_pr['profile'] = dict( + type='APPLICATION_PROFILE_TYPE_UDP', + udp_fast_path_profile=dict( + session_idle_timeout=lb_pr['idle_timeout'] + + ) + ) + +def convert(alb_config, nsx_lb_config): + alb_config['ApplicationProfile'] = list() + alb_config['NetworkProfile'] = list() + for lb_pr in nsx_lb_config['LbAppProfiles']: + alb_pr=dict( + name=lb_pr['display_name'] + ) + update_alb_type(lb_pr, alb_pr) + if lb_pr['resource_type'] == 'LBHttpProfile': + alb_config['ApplicationProfile'].append(alb_pr) + else: + alb_config['NetworkProfile'].append(alb_pr) diff --git a/python/avi/migrationtools/nsxt_converter/test_cd.py b/python/avi/migrationtools/nsxt_converter/test_cd.py new file mode 100644 index 0000000000..012b09e5dd --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/test_cd.py @@ -0,0 +1,12 @@ + +from avi.migrationtools.nsxt_converter import v_client + +if __name__ == '__main__': + client = v_client.VCClient('10.206.102.240', 'rest', + 'Administrator@vsphere.local', 'Admin!23', 'E3:73:FA:B3:8D:81:6E:F2:2A:93:5C:E6:15:04:12:B3:8D:AD:98:5A:30:B0:39:32:A1:72:E9:00:71:94:30:6E') + + url = "/4.0/edges/%s/interfaces" % ('edge-2') + response = client.get(endpoint=url) + if response: + print(response.json()) + # print (client) \ No newline at end of file diff --git a/python/avi/migrationtools/nsxt_converter/v_client.py b/python/avi/migrationtools/nsxt_converter/v_client.py new file mode 100755 index 0000000000..ac42d8f5ae --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/v_client.py @@ -0,0 +1,51 @@ +import requests +from avi.migrationtools.nsxt_converter import base_client + + +requests.packages.urllib3.disable_warnings() + +class NSXVClient(base_client.NSXClient): + + def get_list_results(self, endpoint, params=None): + """ + Query method for json API get for list (takes care of pagination) + """ + response = self.get(endpoint, params).json() + for _, value in response.items(): + # Only one key and value present + if 'data' not in value: + return [] + + data = value['data'] + if 'pagingInfo' not in value: + return data + + paging_info = value['pagingInfo'] + page_size = int(paging_info['pageSize']) + total_count = int(paging_info['totalCount']) + if total_count <= page_size: + return data + + pages = int(total_count/page_size) + if page_size * pages < total_count: + pages += 1 + self.logger.info("Total pages to retrieve for url %s is %d" % (endpoint, pages)) + for i in range(1, pages): + start_index = page_size * i + if params: + params.update({'startindex': start_index}) + else: + params = {'startindex': start_index} + + response = self.get(endpoint, params=params) + if response: + for _, v in response.json().items(): + data += v['data'] + + return data + +class VCClient(base_client.NSXClient): + + def __init__(self, host, prefix, username=None, password=None, thumbprint=None, logger=None): + super().__init__(host, prefix, username=username, password=password, logger=logger) + self.thumbprint = thumbprint diff --git a/python/avi/migrationtools/nsxt_converter/vs_converter.py b/python/avi/migrationtools/nsxt_converter/vs_converter.py new file mode 100644 index 0000000000..1b19761b41 --- /dev/null +++ b/python/avi/migrationtools/nsxt_converter/vs_converter.py @@ -0,0 +1,23 @@ + +def update_alb_type(lb_vs, alb_vs): + alb_vs['enabled'] = lb_vs['enabled'] + alb_vs['vip']=lb_vs.get('ip_address') + alb_vs['services']=dict( + port=lb_vs['ports'][0] + ) + alb_vs['pool_ref']=lb_vs['pool_path'] + alb_vs['application_profile_ref']=lb_vs['application_profile_path'] + alb_vs['ssl_profile_ref']=lb_vs.get('client_ssl_profile_binding') + +def convert(alb_config, nsx_lb_config): + alb_config['VirtualService'] = list() + + for lb_vs in nsx_lb_config['LBVirtualServers']: + alb_vs = dict( + name=lb_vs['display_name'], + + ) + + update_alb_type(lb_vs, alb_vs) + + alb_config['VirtualService'].append(alb_vs)