def output(output): '''Example for all possible Echo Formats You see the message only, if the Output TEXT ''' with OutputFormat(output): action('This is a ok:') ok() action('This is a ok with message:') ok('all is fine') action('This is a warning:') warning('please check this') with Action('Start with working..') as act: # save_the_world() act.progress() act.progress() act.progress() act.progress() print_table('id name'.split(), [{'id': 1, 'name': 'Test #1'}, {'id': 2, 'name': 'Test #2'}]) info('Only FYI') action('This is a error:') error('this is wrong, please fix') action('This is a fatal error:') fatal_error('this is a fuckup') info('I\'am not printed, the process a dead')
def check_schedulers(r, schedulers): for s in schedulers: action('Check scheduler {} .....'.format(s[2:])) try: ts = r.get("zmon:metrics:{}:ts".format(s)) if ts is None: error("No scheduling loop registered ( running/stuck? )") continue delta = int(time.time() - float(ts)) action("... last loop") highlight("{}".format(delta)) action("s ago ...") if delta > 300: error("Last loop more than 300s ago (stuck? restart?)".format(delta)) continue if delta > 180: error("Last loop more than 180s ago (stuck? check logs/watch)".format(delta)) continue action("...") ok() except Exception as e: error(e)
def updateAlertDef(yaml_file): """update a single check definition""" data = get_config_data() post = yaml.safe_load(yaml_file) post['last_modified_by'] = data['user'] if 'status' not in post: post['status'] = 'ACTIVE' action('Updating alert definition..') if 'id' not in post: error('"id" missing in definition') return if 'check_definition_id' not in post: error('"check_definition_id" missing in definition') return alert_id = post['id'] r = requests.put(data['url'] + '/alert-definitions/{}'.format(alert_id), json.dumps(post), auth=HTTPBasicAuth(data['user'], data['password']), headers={'Content-Type': 'application/json'}) if r.status_code == 200: ok(get_config_data()["url"].replace("rest/api/v1", "") + "#/alert-details/" + str(r.json()["id"])) else: print(r.text)
def updateAlertDef(yaml_file): """update a single check definition""" data = get_config_data() alert = yaml.safe_load(yaml_file) alert['last_modified_by'] = data.get('user', 'unknown') if 'status' not in alert: alert['status'] = 'ACTIVE' action('Updating alert definition..') if 'id' not in alert: error('"id" missing in definition') return if 'check_definition_id' not in alert: error('"check_definition_id" missing in definition') return alert_id = alert['id'] r = put('/alert-definitions/{}'.format(alert_id), json.dumps(alert)) if r.status_code != 200: error(r.text) r.raise_for_status() ok(get_base_url(get_config_data()["url"]) + "#/alert-details/" + str(r.json()["id"]))
def change_version_traffic(stack_ref: StackReference, percentage: float, region: str): versions = list(get_stack_versions(stack_ref.name, region)) arns = [] for each_version in versions: arns = arns + each_version.notification_arns identifier_versions = collections.OrderedDict( (version.identifier, version.version) for version in versions) version = get_version(versions, stack_ref.version) identifier = version.identifier if not version.domain: raise click.UsageError('Stack {} version {} has ' 'no domain'.format(version.name, version.version)) percentage = int(percentage * PERCENT_RESOLUTION) known_record_weights, partial_count, partial_sum = get_weights(version.dns_name, identifier, identifier_versions.keys()) if partial_count == 0 and percentage == 0: # disable the last remaining version new_record_weights = {i: 0 for i in known_record_weights.keys()} message = ('DNS record "{dns_name}" will be removed from that ' 'stack'.format(dns_name=version.dns_name)) ok(msg=message) else: with Action('Calculating new weights..'): compensations = {} if partial_count: delta = int((FULL_PERCENTAGE - percentage - partial_sum) / partial_count) else: delta = 0 if percentage > 0: # will put the only last version to full traffic percentage compensations[identifier] = FULL_PERCENTAGE - percentage percentage = int(FULL_PERCENTAGE) new_record_weights, deltas = calculate_new_weights(delta, identifier, known_record_weights, percentage) total_weight = sum(new_record_weights.values()) calculation_error = FULL_PERCENTAGE - total_weight if calculation_error and calculation_error < FULL_PERCENTAGE: compensate(calculation_error, compensations, identifier, new_record_weights, partial_count, percentage, identifier_versions) assert sum(new_record_weights.values()) == FULL_PERCENTAGE message = dump_traffic_changes(stack_ref.name, identifier, identifier_versions, known_record_weights, new_record_weights, compensations, deltas) print_traffic_changes(message) inform_sns(arns, message, region) set_new_weights(version.dns_name, identifier, version.lb_dns_name, new_record_weights, region)
def push_entity(ctx, entity): if entity[-4:] == "json" and os.path.exists(entity): with open(entity, 'rb') as file: entity = file.read() data = json.loads(entity.decode()) elif entity[-4:] == 'yaml' and os.path.exists(entity): with open(entity, 'rb') as fd: data = yaml.safe_load(fd) else: data = json.loads(entity) if not isinstance(data, list): data = [data] for e in data: action("creating entity...{}".format(e['id'])) try: entity = json.dumps(e) r = put('/entities/', entity) if r.status_code == 200: ok() else: error() except: error("failed")
def init(yaml_file): """Initialize a new alert definition YAML file""" name = click.prompt('Alert name', default='Example Alert') check_id = click.prompt('Check ID') team = click.prompt('(Responsible-) Team', default='Example Team') data = { 'check_definition_id': check_id, 'condition': '>100', 'description': 'Example Alert Description', 'entities': [], 'entities_exclude': [], 'id': '', 'name': name, 'parameters': {}, 'parent_id': '', 'priority': 2, 'responsible_team': team, 'status': 'ACTIVE', 'tags': [], 'team': team, 'template': False, } yaml_file.write(dump_yaml(data).encode('utf-8')) ok()
def group_remove(ctx, group_name, user_name): action("Removing user ....") r = delete("/groups/{}/member/{}/".format(group_name, user_name)) if r.text == '1': ok() else: error("failed to remove")
def group_add(ctx, group_name, user_name): action("Adding user ....") r = put("/groups/{}/member/{}/".format(group_name, user_name)) if r.text == '1': ok() else: error("failed to insert")
def init(yaml_file): """Initialize a new check definition YAML file""" # NOTE: sorted like FIELD_SORT_INDEX name = click.prompt('Check definition name', default='Example Check') owning_team = click.prompt( 'Team owning this check definition (i.e. your team)', default='Example Team') data = { 'name': name, 'owning_team': owning_team, 'description': "Example ZMON check definition which returns a HTTP status code.\n" + "You can write multiple lines here, including unicode ☺", 'command': "# GET request on example.org and return HTTP status code\n" + "http('http://example.org/', timeout=5).code()", 'interval': 60, 'entities': [{ 'type': 'GLOBAL' }], 'status': 'ACTIVE' } yaml_file.write(dump_yaml(data).encode('utf-8')) ok()
def add_phone(ctx, member_email, phone_nr): action("Adding phone ....") r = put("/groups/{}/phone/{}/".format(member_email, phone_nr)) if r.text == '1': ok() else: error("failed to set phone")
def remove_phone(ctx, member_email, phone_nr): action("Removing phone number ....") r = delete("/groups/{}/phone/{}/".format(member_email, phone_nr)) if r.text == '1': ok() else: error("failed to remove phone")
def output(output): '''Example for all possible Echo Formats You see the message only, if the Output TEXT ''' with OutputFormat(output): action('This is a ok:') ok() action('This is a ok with message:') ok('all is fine') action('This is a warning:') warning('please check this') with Action('Start with working..') as act: # save_the_world() act.progress() act.progress() act.progress() act.progress() print_table('id name'.split(), [{ 'id': 1, 'name': 'Test #1' }, { 'id': 2, 'name': 'Test #2' }]) info('Only FYI') action('This is a error:') error('this is wrong, please fix') action('This is a fatal error:') fatal_error('this is a fuckup') info('I\'am not printed, the process a dead')
def change_version_traffic(stack_ref: StackReference, percentage: float, region: str): versions = list(get_stack_versions(stack_ref.name, region)) arns = [] for each_version in versions: arns = arns + each_version.notification_arns identifier_versions = collections.OrderedDict( (version.identifier, version.version) for version in versions) version = get_version(versions, stack_ref.version) identifier = version.identifier if not version.domain: raise click.UsageError('Stack {} version {} has ' 'no domain'.format(version.name, version.version)) percentage = int(percentage * PERCENT_RESOLUTION) known_record_weights, partial_count, partial_sum = get_weights(version.dns_name, identifier, identifier_versions.keys()) if partial_count == 0 and percentage == 0: # disable the last remaining version new_record_weights = {i: 0 for i in known_record_weights.keys()} message = ('DNS record "{dns_name}" will be removed from that ' 'stack'.format(dns_name=version.dns_name)) ok(msg=message) else: with Action('Calculating new weights..'): compensations = {} if partial_count: delta = int((FULL_PERCENTAGE - percentage - partial_sum) / partial_count) else: delta = 0 if percentage > 0: # will put the only last version to full traffic percentage compensations[identifier] = FULL_PERCENTAGE - percentage percentage = int(FULL_PERCENTAGE) new_record_weights, deltas = calculate_new_weights(delta, identifier, known_record_weights, percentage) total_weight = sum(new_record_weights.values()) calculation_error = FULL_PERCENTAGE - total_weight if calculation_error and calculation_error < FULL_PERCENTAGE: compensate(calculation_error, compensations, identifier, new_record_weights, partial_count, percentage, identifier_versions) assert sum(new_record_weights.values()) == FULL_PERCENTAGE message = dump_traffic_changes(stack_ref.name, identifier, identifier_versions, known_record_weights, new_record_weights, compensations, deltas) print_traffic_changes(message) inform_sns(arns, message, region) set_new_weights(version.dns_name, known_record_weights, new_record_weights, region)
def push_entity(obj, entity): """Push one or more entities""" client = get_client(obj.config) if (entity.endswith('.json') or entity.endswith('.yaml')) and os.path.exists(entity): with open(entity, 'rb') as fd: data = yaml.safe_load(fd) else: data = json.loads(entity) if not isinstance(data, list): data = [data] with Action('Creating new entities ...', nl=True) as act: for e in data: action('Creating entity {} ...'.format(e['id'])) try: client.add_entity(e) ok() except ZmonArgumentError as e: act.error(str(e)) except requests.HTTPError as e: log_http_exception(e, act) except Exception as e: act.error('Failed: {}'.format(str(e)))
def get_tv_token(obj): """Retrieve a new token""" client = get_client(obj.config) with Action('Retrieving new one-time token ...', nl=True): token = client.get_onetime_token() ok(client.token_login_url(token.strip('"')))
def invoke(op, *args, **kwargs): if op.http_method != 'get': clickclick.action('Invoking..') request = construct_request(op, {}, **kwargs) c = RequestsClient() future = c.request(request) future.result() clickclick.ok()
def switch_active(ctx, group_name, user_name): action("Switching active user ....") r = delete("/groups/{}/active/".format(group_name)) r = put("/groups/{}/active/{}/".format(group_name, user_name)) if r.text == '1': ok() else: error("failed to switch")
def delete_check_definition(check_id): '''Delete an orphan check definition''' action('delete check id {} ...'.format(check_id)) r = delete('/check-definitions/{}'.format(check_id)) if r.status_code == 200: ok() else: error(r.text)
def check_redis_host(host, port=6379): action("Check Redis on {}".format(host)) action("...") try: r = StrictRedis(host, port) workers = r.smembers("zmon:metrics") ok() return r, workers except Exception as e: error(e)
def delete_entity(ctx, entity_id): action("delete entity... {}".format(entity_id)) try: r = delete('/entities/?id={}'.format(urllib.parse.quote_plus(entity_id))) if r.status_code == 200 and r.text == "1": ok() else: error("Delete unsuccessfull") except Exception as ex: error("Exception during delete: " + str(ex))
def check_queues(redis): queues = ['zmon:queue:default', 'zmon:queue:snmp', 'zmon:queue:internal', 'zmon:queue:secure'] for q in queues: action('Checking queue length ... {} ...'.format(q)) l = redis.llen(q) action("...") highlight("{}".format(l)) action(" ...") if l < 2000: ok() continue error("to many tasks")
def create_alert_definition(obj, yaml_file): """Create a single alert definition""" client = get_client(obj.config) alert = yaml.safe_load(yaml_file) alert['last_modified_by'] = obj.config.get('user', 'unknown') with Action('Creating alert definition ...', nl=True) as act: try: new_alert = client.create_alert_definition(alert) ok(client.alert_details_url(new_alert)) except ZmonArgumentError as e: act.error(str(e))
def dashboard_update(obj, yaml_file): """Create/Update a single ZMON dashboard""" client = get_client(obj.config) dashboard = {} with open(yaml_file, 'rb') as f: dashboard = yaml.safe_load(f) msg = 'Creating new dashboard ...' if 'id' in dashboard: msg = 'Updating dashboard {} ...'.format(dashboard.get('id')) with Action(msg, nl=True): dash_id = client.update_dashboard(dashboard) ok(client.dashboard_url(dash_id))
def grafana_update(obj, yaml_file): """Create/Update a single ZMON dashboard""" dashboard = yaml.safe_load(yaml_file) title = dashboard.get('dashboard', {}).get('title', '') client = get_client(obj.config) with Action('Updating dashboard {} ...'.format(title), nl=True) as act: try: client.update_grafana_dashboard(dashboard) ok(client.grafana_dashboard_url(dashboard)) except ZmonArgumentError as e: act.error(e)
def update(yaml_file): """update a single check definition""" data = get_config_data() post = yaml.safe_load(yaml_file) post['last_modified_by'] = data['user'] if 'status' not in post: post['status'] = 'ACTIVE' action('Updating check definition... ') r = requests.post(data['url'] + '/check-definitions', json.dumps(post), auth=HTTPBasicAuth(data['user'], data['password']), headers={'Content-Type': 'application/json'}) if r.status_code == 200: ok(get_config_data()["url"].replace("rest/api/v1", "") + "#/check-definitions/view/" + str(r.json()["id"])) else: print(r.text)
def change_version_traffic(stack_ref: StackReference, percentage: float, region): versions = list(get_stack_versions(stack_ref.name, region)) identifier_versions = collections.OrderedDict( (version.identifier, version.version) for version in versions) version = get_version(versions, stack_ref.version) identifier = version.identifier if not version.domain: raise click.UsageError('Stack {} version {} has no domain'.format(version.name, version.version)) domain = version.domain.split('.', 1)[1] zone = get_zone(region, domain) rr = zone.get_records() percentage = int(percentage * PERCENT_RESOLUTION) known_record_weights, partial_count, partial_sum = get_weights(version.dns_name, identifier, rr, identifier_versions.keys()) if partial_count == 0 and percentage == 0: # disable the last remaining version new_record_weights = {i: 0 for i in known_record_weights.keys()} ok(msg='DNS record "{dns_name}" will be removed from that stack'.format(dns_name=version.dns_name)) else: with Action('Calculating new weights..'): compensations = {} if partial_count: delta = int((FULL_PERCENTAGE - percentage - partial_sum) / partial_count) else: delta = 0 if percentage > 0: # will put the only last version to full traffic percentage compensations[identifier] = FULL_PERCENTAGE - percentage percentage = int(FULL_PERCENTAGE) new_record_weights, deltas = calculate_new_weights(delta, identifier, known_record_weights, percentage) total_weight = sum(new_record_weights.values()) calculation_error = FULL_PERCENTAGE - total_weight if calculation_error and calculation_error < FULL_PERCENTAGE: percentage = compensate(calculation_error, compensations, identifier, new_record_weights, partial_count, percentage, identifier_versions) assert sum(new_record_weights.values()) == FULL_PERCENTAGE dump_traffic_changes(stack_ref.name, identifier, identifier_versions, known_record_weights, new_record_weights, compensations, deltas) set_new_weights(version.dns_name, identifier, version.lb_dns_name, new_record_weights, percentage, rr)
def test_echo(): action('Action..') ok() action('Action..') error(' some error') action('Action..') with pytest.raises(SystemExit): fatal_error(' some fatal error') # noqa action('Action..') warning(' some warning') info('Some info')
def update(obj, yaml_file, skip_validation): """Update a single check definition""" check = yaml.safe_load(yaml_file) check['last_modified_by'] = obj.get('user', 'unknown') client = get_client(obj.config) with Action('Updating check definition ...', nl=True) as act: try: check = client.update_check_definition( check, skip_validation=skip_validation) ok(client.check_definition_url(check)) except ZmonArgumentError as e: act.error(str(e))
def status(config): """check system status""" redis, workers = check_redis_host(config['redis_host'], 6379) print("") workers = list(map(lambda x: x.decode(), sorted(workers))) action("Looking for <30s interval scheduler ...") scheduler = list(filter(lambda x: x[:7] == 's-p3423', workers)) if not scheduler: error("not found! check p3423") else: action("... running {}".format(scheduler[0][2:])) ok() action("Looking for >30s interval scheduler ...") scheduler = list(filter(lambda x: x[:7] == 's-p3422', workers)) if not scheduler: error("not found! check p3422") else: action("... running {}".format(scheduler[0][2:])) ok() action("Looking for NG scheduler ...") scheduler = list(filter(lambda x: x == 's-p3421.monitor02', workers)) if not scheduler: error("not found! check p3421 on monitor02") else: action("... running {}".format(scheduler[0][2:])) ok() action("Looking for self monitoring scheduler ...") scheduler = list(filter(lambda x: x == 's-p3421.itr-monitor01', workers)) if not scheduler: error("not found! check p3411 on itr-monitor02") else: action("... running {}".format(scheduler[0][2:])) ok() print("") ws = [] ss = [] for w in workers: if w[:2] == "s-": ss.append(w) else: ws.append(w) check_schedulers(redis, ss) print("") check_queues(redis) print("") check_workers(redis, ws)
def update(yaml_file): """update a single check definition""" data = get_config_data() check = yaml.safe_load(yaml_file) check['last_modified_by'] = data.get('user', 'unknown') if 'status' not in check: check['status'] = 'ACTIVE' action('Updating check definition... ') r = post('/check-definitions', json.dumps(check)) if r.status_code != 200: error(r.text) r.raise_for_status() ok(get_base_url(get_config_data()["url"]) + "#/check-definitions/view/" + str(r.json()["id"]))
def create_alert_definition(yaml_file): """Create a single alert definition""" data = get_config_data() alert = yaml.safe_load(yaml_file) alert['last_modified_by'] = data.get('user', 'unknown') if 'status' not in alert: alert['status'] = 'ACTIVE' action('Creating alert definition..') if 'check_definition_id' not in alert: error('"check_definition_id" missing in definition') return r = post('/alert-definitions', json.dumps(alert)) ok(get_base_url(get_config_data()["url"]) + "#/alert-details/" + str(r.json()["id"]))
def login(config, url): '''Login to Pier One Docker registry (generates docker configuration in ~/.docker/config.json)''' url_option_was_set = url url = set_pierone_url(config, url) if not url_option_was_set: stups_cli.config.store_config(config, 'pierone') # Check if the credential helper is available if shutil.which("docker-credential-pierone") is None: fatal_error( "docker-credential-pierone executable is not available. " "If you've installed `pierone` to a virtual environment, make sure to add it to to the PATH." ) docker_login_with_credhelper(url) ok("Authentication configured for {}, you don't need to run pierone login anymore!" .format(url))
def update(yaml_file): """update a single check definition""" data = get_config_data() check = yaml.safe_load(yaml_file) check['last_modified_by'] = data.get('user', 'unknown') if 'status' not in check: check['status'] = 'ACTIVE' action('Updating check definition... ') if not check.get('owning_team'): raise click.UsageError('Missing "owning_team" in check definition') validate_check_command(check['command']) r = post('/check-definitions', json.dumps(check)) ok(get_base_url(get_config_data()["url"]) + "#/check-definitions/view/" + str(r.json()["id"]))
def check_workers(r, workers): for w in workers: action('Check worker {} ...'.format(w)) try: ts = r.get("zmon:metrics:{}:ts".format(w)) delta = time.time() - float(ts) delta = max(int(delta), 0) action("... last exec") highlight("{}".format(delta)) action("s ago ...") if delta < 30: ok() continue error("no task execute recently") except Exception as e: error(e)
def dashboard_update(ctx, yaml_file): """Create/Update a single ZMON dashboard""" with open(yaml_file, 'rb') as f: data = yaml.safe_load(f) if 'id' in data: action('Updating dashboard {}..'.format(data.get('id'))) post('/dashboard/{}'.format(data['id']), json.dumps(data)) ok() else: action('Creating new dashboard..') r = post('/dashboard/', json.dumps(data)) data['id'] = int(r.text) with open(yaml_file, 'wb') as f: f.write(dump_yaml(data).encode('utf-8')) ok("new id: {}".format(r.text))
def push_entity(ctx, entity): '''Push one or more entities''' if (entity.endswith('.json') or entity.endswith('.yaml')) and os.path.exists(entity): # JSON is a subset of YAML, so we can use the YAML parser.. with open(entity, 'rb') as fd: data = yaml.safe_load(fd) else: data = json.loads(entity) if not isinstance(data, list): data = [data] for e in data: action("Creating entity {}..".format(e['id'])) try: entity = json.dumps(e) put('/entities/', entity) ok() except: error("failed")
def update_alert_definition(obj, yaml_file): """Update a single alert definition""" alert = yaml.safe_load(yaml_file) alert['last_modified_by'] = obj.config.get('user', 'unknown') client = get_client(obj.config) with Action('Updating alert definition ...', nl=True) as act: try: # Workaround API inconsistency! if alert.get('parameters'): for k, v in alert['parameters'].items(): if type(v) is str: alert['parameters'][k] = json.loads(v) client.update_alert_definition(alert) ok(client.alert_details_url(alert)) except ZmonArgumentError as e: act.error(str(e))
def push_entity(ctx, entity): if entity[-4:] == "json" and os.path.exists(entity): action("create or update entity from json ...") with open(entity, 'rb') as file: entity = file.read() elif entity[-4:] == 'yaml' and os.path.exists(entity): action("create or update entity from yaml ...") with open(entity, 'rb') as fd: data = yaml.safe_load(fd) entity = json.dumps(data) else: action("create or update entity...") try: r = put('/entities/', entity) if r.status_code == 200: ok() else: error() except: error("failed")
def init(obj, yaml_file): """Initialize a new dashboard YAML file""" name = click.prompt('Dashboard name', default='Example dashboard') alert_teams = click.prompt('Alert Teams (comma separated)', default='Team1, Team2') user = obj.config.get('user', 'unknown') data = { 'id': '', 'name': name, 'last_modified_by': user, 'alert_teams': [t.strip() for t in alert_teams.split(',')], 'tags': [], 'view_mode': 'FULL', 'shared_teams': [], 'widget_configuration': [], } yaml_file.write(dump_yaml(data).encode('utf-8')) ok()
def grafana_update(ctx, yaml_file): """Create/Update a single ZMON dashboard""" with open(yaml_file, 'rb') as f: data = yaml.safe_load(f) title = data.get('dashboard', {}).get('title', None) id = data.get('dashboard', {}).get('id', None) if id is None and title is None: error("id and title missing") if title is None: error("title is missing") action('Updating dashboard title "{}"...'.format(title)) r = post('/grafana2-dashboards', json.dumps(data)) if r.status_code == 200: ok() else: error(r.text)
def set_new_weights(dns_name, identifier, lb_dns_name: str, new_record_weights, percentage, rr): action('Setting weights for {dns_name}..', **vars()) did_the_upsert = False for r in rr: if r.type == 'CNAME' and r.name == dns_name: w = new_record_weights[r.identifier] if w: if int(r.weight) != w: r.weight = w rr.add_change_record('UPSERT', r) if identifier == r.identifier: did_the_upsert = True else: rr.add_change_record('DELETE', r) if new_record_weights[identifier] > 0 and not did_the_upsert: change = rr.add_change('CREATE', dns_name, 'CNAME', ttl=20, identifier=identifier, weight=new_record_weights[identifier]) change.add_value(lb_dns_name) if rr.changes: rr.commit() if sum(new_record_weights.values()) == 0: ok(' DISABLED') else: ok() else: ok(' not changed')
def set_new_weights(dns_names: list, identifier, lb_dns_name: str, new_record_weights, percentage): action('Setting weights for {dns_names}..', dns_names=', '.join(dns_names)) dns_changes = collections.defaultdict(lambda: []) for idx, dns_name in enumerate(dns_names): domain = dns_name.split('.', 1)[1] hosted_zone = Route53HostedZone.get_by_domain_name(domain) did_the_upsert = False convert_domain_records_to_alias(dns_name) for r in Route53.get_records(name=dns_name): if r.type in [RecordType.CNAME, RecordType.A, RecordType.AAAA]: w = new_record_weights[r.set_identifier] if w: if int(r.weight) != w: r.weight = w dns_changes[hosted_zone.id].append({'Action': 'UPSERT', 'ResourceRecordSet': r.boto_dict}) if identifier == r.set_identifier: did_the_upsert = True else: if dns_changes.get(hosted_zone.id) is None: dns_changes[hosted_zone.id] = [] dns_changes[hosted_zone.id].append({'Action': 'DELETE', 'ResourceRecordSet': r.boto_dict.copy()}) if new_record_weights[identifier] > 0 and not did_the_upsert: if dns_changes.get(hosted_zone.id) is None: dns_changes[hosted_zone.id] = [] elb = ELB.get_by_dns_name(lb_dns_name[idx]) record = Route53Record(name=dns_name, type=RecordType.A, set_identifier=identifier, weight=new_record_weights[identifier], alias_target={"HostedZoneId": elb.hosted_zone.id, "DNSName": lb_dns_name[idx], "EvaluateTargetHealth": False}) dns_changes[hosted_zone.id].append({'Action': 'UPSERT', 'ResourceRecordSet': record.boto_dict}) if dns_changes: route53 = boto3.client('route53') for hosted_zone_id, change in dns_changes.items(): route53.change_resource_record_sets(HostedZoneId=hosted_zone_id, ChangeBatch={'Comment': 'Weight change of {}'.format(hosted_zone_id), 'Changes': change}) if sum(new_record_weights.values()) == 0: ok(' DISABLED') else: ok() else: ok(' not changed')
def set_new_weights(dns_names: list, identifier, lb_dns_name: str, new_record_weights, percentage): action('Setting weights for {dns_names}..', dns_names=', '.join(dns_names)) dns_changes = {} for idx, dns_name in enumerate(dns_names): domain = dns_name.split('.', 1)[1] zone = get_zone(domain) did_the_upsert = False for r in get_records(domain): if r['Type'] == 'CNAME' and r['Name'] == dns_name: w = new_record_weights[r['SetIdentifier']] if w: if int(r['Weight']) != w: r['Weight'] = w if dns_changes.get(zone['Id']) is None: dns_changes[zone['Id']] = [] dns_changes[zone['Id']].append({'Action': 'UPSERT', 'ResourceRecordSet': r}) if identifier == r['SetIdentifier']: did_the_upsert = True else: if dns_changes.get(zone['Id']) is None: dns_changes[zone['Id']] = [] dns_changes[zone['Id']].append({'Action': 'DELETE', 'ResourceRecordSet': r.copy()}) if new_record_weights[identifier] > 0 and not did_the_upsert: if dns_changes.get(zone['Id']) is None: dns_changes[zone['Id']] = [] dns_changes[zone['Id']].append({'Action': 'UPSERT', 'ResourceRecordSet': {'Name': dns_name, 'Type': 'CNAME', 'SetIdentifier': identifier, 'Weight': new_record_weights[identifier], 'TTL': 20, 'ResourceRecords': [{'Value': lb_dns_name[idx]}]}}) if dns_changes: route53 = boto3.client('route53') for hosted_zone_id, change in dns_changes.items(): route53.change_resource_record_sets(HostedZoneId=hosted_zone_id, ChangeBatch={'Comment': 'Weight change of {}'.format(hosted_zone_id), 'Changes': change}) if sum(new_record_weights.values()) == 0: ok(' DISABLED') else: ok() else: ok(' not changed')
def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is None: if self.output == 'text' and not self.printer and not self.errors: ok(self.ok_msg) elif not self._suppress_exception: error(' EXCEPTION OCCURRED: {}'.format(exc_val))
def set_new_weights(dns_names: list, identifier, lb_dns_name: str, new_record_weights: Dict, region: str): action('Setting weights for {dns_names}..', dns_names=', '.join(dns_names)) for idx, dns_name in enumerate(dns_names): domain = dns_name.split('.', 1)[1] hosted_zone = Route53HostedZone.get_by_domain_name(domain) convert_cname_records_to_alias(dns_name) changed = False for stack_name, percentage in new_record_weights.items(): try: stack = CloudFormationStack.get_by_stack_name(stack_name, region=region) except StackNotFound: # The Route53 record doesn't have an associated stack # fallback to the old logic record = None for r in Route53.get_records(name=dns_name): if r.set_identifier == stack_name: record = r break if percentage: record.weight = percentage hosted_zone.upsert( [record], comment="Change weight of {} to {}".format( stack_name, percentage)) else: hosted_zone.delete( [record], comment="Delete {} " "because traffic for it is 0".format(stack_name)) changed = True continue for key, resource in stack.template['Resources'].items(): if (resource['Type'] == ResourceType.route53_record_set and resource['Properties']['Name'] == dns_name): dns_record = stack.template['Resources'][key] break try: dns_record['Properties']['Weight'] = percentage except NameError: raise ELBNotFound(dns_name) try: stack.update() except StackNotUpdated: # make sure we update DNS records which were not updated via CloudFormation record = None for r in Route53.get_records(name=dns_name): if r.set_identifier == stack_name: record = r break if record and record.weight != percentage: record.weight = percentage hosted_zone.upsert( [record], comment="Change weight of {} to {}".format( stack_name, percentage)) changed = True else: changed = True if changed: ok() else: ok(' not changed')
def set_new_weights(dns_names: list, old_record_weights: Dict, new_record_weights: Dict, region: str): action("Setting weights for {dns_names}..", dns_names=", ".join(dns_names)) changed = False updates = {} for idx, dns_name in enumerate(dns_names): domain = dns_name.split(".", 1)[1] hosted_zone = Route53HostedZone.get_by_domain_name(domain) convert_cname_records_to_alias(dns_name) for stack_name, percentage in new_record_weights.items(): if old_record_weights[stack_name] == percentage: # Stack weight will not change continue try: if stack_name not in updates.keys(): stack = CloudFormationStack.get_by_stack_name( stack_name, region=region) else: stack = updates[stack_name]["stack"] except StackNotFound: # The Route53 record doesn't have an associated stack # fallback to the old logic record = None for r in Route53.get_records(name=dns_name): if r.set_identifier == stack_name: record = r break if percentage: record.weight = percentage hosted_zone.upsert( [record], comment="Change weight of {} to {}".format( stack_name, percentage), ) else: hosted_zone.delete( [record], comment="Delete {} " "because traffic for it is 0".format(stack_name), ) changed = True continue for key, resource in stack.template["Resources"].items(): if (resource["Type"] == ResourceType.route53_record_set and resource["Properties"]["Name"] == dns_name): dns_record = stack.template["Resources"][key] break try: dns_record["Properties"]["Weight"] = percentage except NameError: raise ELBNotFound(dns_name) if stack_name not in updates.keys(): update = {"stack": stack, "zones": {}} updates[stack_name] = update else: update = updates[stack_name] if domain not in update["zones"].keys(): records = list() update["zones"][domain] = records else: records = update["zones"][domain] record = None for r in Route53.get_records(name=dns_name): if r.set_identifier == stack_name: record = r break if record and record.weight != percentage: record.weight = percentage records.append({ "record": record, "comment": "Change weight of {} to {}".format(stack_name, percentage), }) for key, update in updates.items(): try: update["stack"].update() except StackNotUpdated: # make sure we update DNS records which were not updated via CloudFormation for domain, records in update["zones"].items(): hosted_zone = Route53HostedZone.get_by_domain_name(domain) for zone_update in records: hosted_zone.upsert([zone_update["record"]], comment=zone_update["comment"]) changed = True else: changed = True if changed: ok() else: ok(" not changed")