import datetime import os import time import requests from requests.adapters import HTTPAdapter from requests.packages.urllib3.util.retry import Retry import yaml # setup requests session for connection retries session = requests.Session() retry = Retry(connect=3, backoff_factor=0.5) adapter = HTTPAdapter(max_retries=retry) session.mount('http://', adapter) session.mount('https://', adapter) # stat trackers count = 1 start_time = time.time() total_sleep_time = 0 def request_retry(http_method, url, headers, valid_codes, body=None): while True: response = http_method(url, headers=headers, json=body) if response.status_code in valid_codes: return response elif response.status_code == 429: sleep_time = max(response.headers['X-RateLimit-Reset-Seconds-IP'], response.headers['X-RateLimit-Remaining-Org']) sleep_time = int(sleep_time) * 1.5 global total_sleep_time total_sleep_time += sleep_time print('rate limited, sleeping for {} (total {})'.format(sleep_time, total_sleep_time)) time.sleep(int(sleep_time)*2) else: exception_message = 'Invalid response received for {}: {} {}'.format(url, response.json(), response.headers) raise Exception(exception_message) with open('features.yml', 'r') as stream: features_data_list = yaml.safe_load(stream) auth_token = os.environ.get('SPLIT_AUTH_TOKEN') headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {auth_token}'} SPLIT_V2_API = 'https://api.split.io/internal/api/v2' SPLIT_ENVIRONMENT = os.environ.get('SPLIT_ENVIRONMENT', 'dev') workspaces = session.get(f'{SPLIT_V2_API}/workspaces', headers=headers).json() workspace_id = workspaces['objects'][0]['id'] total_feature_flags = len(features_data_list) print('Sync {} features'.format(total_feature_flags)) for feature in features_data_list: split_name = feature['name'] create_body = {'name': split_name} def_body = {} def_body['treatments'] = [{'name': 'on', 'description': ''}, {'name': 'off', 'description': ''}] def_body['rules'] = [] def_body['defaultTreatment'] = 'off' def_body['defaultRule'] = [{'treatment': 'off', 'size': 100}] # Create the split percent_done = round(count/total_feature_flags * 100, 2) print('{} Migrating feature_flag {}: {} ({}% done)'.format( datetime.datetime.now(), count, split_name, percent_done)) print('Checking split {} exists in the workspace'.format(split_name)) response = request_retry( session.get, f'{SPLIT_V2_API}/splits/ws/{workspace_id}/{split_name}', headers, [200, 404]) if response.status_code == 404: print('Split does not exist in the workspace - creating it') response = request_retry( session.post, f'{SPLIT_V2_API}/splits/ws/{workspace_id}/trafficTypes/user', headers, [200], create_body) # build targeting rules attribute_types = ('vendor_id', 'identity_id', 'user_id') for attr in attribute_types: try: id_list = feature.get('force').get('enabled').get(f'{attr}s') or feature.get('force').get('control').get(f'{attr}s') except AttributeError: id_list = [] if id_list: condition = {'combiner': 'AND', 'matchers': [{'type': 'IN_LIST_STRING', 'attribute': attr, 'strings': id_list}]} def_body['rules'].append( {'buckets': [ {'treatment': 'on', 'size': 100} ], 'condition': condition }) if feature['variants']['enabled'] == 1: def_body['defaultRule'] = [{'treatment': 'on', 'size': 100}] response = request_retry( session.get, f'{SPLIT_V2_API}/splits/ws/{workspace_id}/{split_name}/environments/{SPLIT_ENVIRONMENT}', headers, [200, 404]) print('Updating split {} in {}'.format(split_name, SPLIT_ENVIRONMENT)) if response.status_code == 200: http_method = session.put elif response.status_code == 404: http_method = session.post response = request_retry( http_method, f'{SPLIT_V2_API}/splits/ws/{workspace_id}/{split_name}/environments/{SPLIT_ENVIRONMENT}', headers, [200], def_body) print('Split creation response: {}'.format(response.json())) count+=1 print('\n\n') end_time = time.time() print('run time {}'.format(end_time-start_time))