Ejemplo n.º 1
0
def set_config_file(config_file=DEFAULT_CONFIG_FILE):
    while True:
        url = click.prompt(
            'Please enter the SLR base URL (e.g. https://slo-metrics.example.com)'
        )

        with Action('Checking {}..'.format(url)):
            requests.get(url, timeout=5, allow_redirects=False)

        zmon_url = click.prompt(
            'Please enter the ZMON URL (e.g. https://demo.zmon.io)')

        with Action('Checking {}..'.format(zmon_url)):
            requests.get(zmon_url, timeout=5, allow_redirects=False)
            break

    data = {
        'url': url,
        'zmon_url': zmon_url,
    }

    fn = os.path.expanduser(config_file)
    with Action('Writing configuration to {}..'.format(fn)):
        with open(fn, 'w') as fd:
            json.dump(data, fd)

    return data
Ejemplo n.º 2
0
def do_respawn_auto_scaling_group(asg_name: str, group: dict, region: str,
                                  instances_to_terminate: set, inplace: bool):
    """
    Respawn ASG.
    """
    asg = BotoClientProxy("autoscaling", region)
    with Action("Suspending scaling processes for {}..".format(asg_name)):
        asg.suspend_processes(AutoScalingGroupName=asg_name,
                              ScalingProcesses=SCALING_PROCESSES_TO_SUSPEND)
    extra_capacity = 0 if inplace else 1
    new_min_size = group["MinSize"] + extra_capacity
    new_max_size = group["MaxSize"] + extra_capacity
    new_desired_capacity = group["DesiredCapacity"] + extra_capacity
    # TODO: error handling (rollback in case of exception?)
    while instances_to_terminate:
        current_group = scale_out(asg, asg_name, region, new_min_size,
                                  new_max_size, new_desired_capacity)
        instance = sorted(instances_to_terminate)[0]
        terminate_instance(asg, region, current_group, instance)
        instances_to_terminate.remove(instance)

    with Action("Resetting Auto Scaling Group to original capacity "
                "({MinSize}-{DesiredCapacity}-{MaxSize})..".format_map(group)):
        asg.update_auto_scaling_group(
            AutoScalingGroupName=asg_name,
            MinSize=group["MinSize"],
            MaxSize=group["MaxSize"],
            DesiredCapacity=group["DesiredCapacity"],
        )

    with Action("Resuming scaling processes for {}..".format(asg_name)):
        asg.resume_processes(AutoScalingGroupName=asg_name)
Ejemplo n.º 3
0
def configure(config):
    '''Configure GitHub access'''
    emails = config.get('emails', [])
    if not emails:
        try:
            emails = [get_git_email()]
        except:
            pass

    emails = click.prompt('Your email addresses (comma separated)',
                          default=','.join(emails) or None)
    token = click.prompt('Your personal GitHub access token',
                         hide_input=True,
                         default=config.get('github_access_token'))

    emails = list([mail.strip() for mail in emails.split(',')])
    config = {'emails': emails, 'github_access_token': token}

    repositories = {}
    with Action('Scanning repositories..') as act:
        for repo in get_repos(token):
            repositories[repo['url']] = repo
            act.progress()

    path = os.path.join(CONFIG_DIR, 'repositories.yaml')
    os.makedirs(CONFIG_DIR, exist_ok=True)
    with open(path, 'w') as fd:
        yaml.safe_dump(repositories, fd)

    with Action('Storing configuration..'):
        stups_cli.config.store_config(config, 'github-maintainer-cli')
Ejemplo n.º 4
0
def do_respawn_auto_scaling_group(asg_name: str, group: dict, region: str,
                                  instances_to_terminate: set,
                                  instances_ok: set, inplace: bool):
    asg = boto3.client('autoscaling', region)
    with Action('Suspending scaling processes for {}..'.format(asg_name)):
        asg.suspend_processes(AutoScalingGroupName=asg_name,
                              ScalingProcesses=SCALING_PROCESSES_TO_SUSPEND)
    extra_capacity = 0 if inplace else 1
    new_min_size = group['MinSize'] + extra_capacity
    new_max_size = group['MaxSize'] + extra_capacity
    new_desired_capacity = group['DesiredCapacity'] + extra_capacity
    # TODO: error handling (rollback in case of exception?)
    while instances_to_terminate:
        current_group = scale_out(asg, asg_name, region, new_min_size,
                                  new_max_size, new_desired_capacity)
        instance = sorted(instances_to_terminate)[0]
        terminate_instance(asg, region, current_group, instance)
        instances_to_terminate.remove(instance)

    with Action(
            'Resetting Auto Scaling Group to original capacity ({}-{}-{})..'.
            format(group['MinSize'], group['DesiredCapacity'],
                   group['MaxSize'])):
        asg.update_auto_scaling_group(AutoScalingGroupName=asg_name,
                                      MinSize=group['MinSize'],
                                      MaxSize=group['MaxSize'],
                                      DesiredCapacity=group['DesiredCapacity'])

    with Action('Resuming scaling processes for {}..'.format(asg_name)):
        asg.resume_processes(AutoScalingGroupName=asg_name)
Ejemplo n.º 5
0
def check_iam_role(application_id: str, bucket_name: str, region: str):
    role_name = 'app-{}'.format(application_id)
    with Action('Checking IAM role {}..'.format(role_name)):
        iam = boto3.client('iam')
        exists = False
        try:
            iam.get_role(RoleName=role_name)
            exists = True
        except:
            pass

    assume_role_policy_document = {'Statement': [{'Action': 'sts:AssumeRole',
                                                  'Effect': 'Allow',
                                                  'Principal': {'Service': 'ec2.amazonaws.com'},
                                                  'Sid': ''}],
                                   'Version': '2008-10-17'}
    if not exists:
        with Action('Creating IAM role {}..'.format(role_name)):
            iam.create_role(RoleName=role_name,
                            AssumeRolePolicyDocument=json.dumps(assume_role_policy_document))

    update_policy = bucket_name is not None and (not exists or
                                                 click.confirm('IAM role {} already exists. '.format(role_name) +
                                                               'Do you want Senza to overwrite the role policy?'))
    if update_policy:
        with Action('Updating IAM role policy of {}..'.format(role_name)):
            policy = get_iam_role_policy(application_id, bucket_name, region)
            iam.put_role_policy(RoleName=role_name,
                                PolicyName=role_name,
                                PolicyDocument=json.dumps(policy))
Ejemplo n.º 6
0
def traffic(stack_name: str,
            stack_version: Optional[str],
            percentage: Optional[int],
            region: Optional[str],
            remote: Optional[str],
            output: Optional[str]):
    '''Manage stack traffic'''
    lizzy = setup_lizzy_client(remote)

    if percentage is None:
        stack_reference = [stack_name]

        with Action('Requesting traffic info..'):
            stack_weights = []
            for stack in lizzy.get_stacks(stack_reference, region=region):
                if stack['status'] in ['CREATE_COMPLETE', 'UPDATE_COMPLETE']:
                    stack_id = '{stack_name}-{version}'.format_map(stack)
                    traffic = lizzy.get_traffic(stack_id, region=region)
                    stack_weights.append({
                        'stack_name': stack_name,
                        'version': stack['version'],
                        'identifier': stack_id,
                        'weight%': traffic['weight']
                    })
        cols = 'stack_name version identifier weight%'.split()
        with OutputFormat(output):
            print_table(cols,
                        sorted(stack_weights, key=lambda x: x['identifier']))
    else:
        with Action('Requesting traffic change..'):
            stack_id = '{stack_name}-{stack_version}'.format_map(locals())
            lizzy.traffic(stack_id, percentage, region=region)
Ejemplo n.º 7
0
def check_s3_bucket(bucket_name: str, region: str):
    with Action("Checking S3 bucket {}..".format(bucket_name)):
        exists = False
        try:
            s3 = boto.s3.connect_to_region(region)
            exists = s3.lookup(bucket_name, validate=True)
        except:
            pass
    if not exists:
        with Action("Creating S3 bucket {}...".format(bucket_name)):
            s3.create_bucket(bucket_name, location=region)
Ejemplo n.º 8
0
def check_iam_role(application_id: str, bucket_name: str, region: str):
    role_name = "app-{}".format(application_id)
    with Action("Checking IAM role {}..".format(role_name)):
        iam = BotoClientProxy("iam")
        try:
            iam.get_role(RoleName=role_name)
            exists = True
        except botocore.exceptions.ClientError:
            exists = False

    assume_role_policy_document = {
        "Statement": [{
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            },
            "Sid": "",
        }],
        "Version":
        "2008-10-17",
    }

    create = False
    if not exists:
        create = confirm(
            "IAM role {} does not exist. "
            "Do you want Senza to create it now?".format(role_name),
            default=True,
        )
        if create:
            with Action("Creating IAM role {}..".format(role_name)):
                iam.create_role(
                    RoleName=role_name,
                    AssumeRolePolicyDocument=json.dumps(
                        assume_role_policy_document),
                )

    attach_mint_read_policy = bucket_name is not None and (
        (not exists and create) or
        (exists
         and confirm("IAM role {} already exists. ".format(role_name) +
                     "Do you want Senza to overwrite the role policy?")))
    if attach_mint_read_policy:
        with Action("Updating IAM role policy of {}..".format(role_name)):
            mint_read_policy = create_mint_read_policy_document(
                application_id, bucket_name, region)
            iam.put_role_policy(
                RoleName=role_name,
                PolicyName=role_name,
                PolicyDocument=json.dumps(mint_read_policy),
            )

    attach_cross_stack_policy(exists, create, role_name, iam)
Ejemplo n.º 9
0
def check_s3_bucket(bucket_name: str, region: str):
    s3 = boto3.resource('s3', region)
    with Action("Checking S3 bucket {}..".format(bucket_name)):
        exists = False
        try:
            s3.meta.client.head_bucket(Bucket=bucket_name)
            exists = True
        except:
            pass
    if not exists:
        with Action("Creating S3 bucket {}...".format(bucket_name)):
            s3.create_bucket(Bucket=bucket_name, CreateBucketConfiguration={'LocationConstraint': region})
Ejemplo n.º 10
0
def create(definition, region, version, parameter, disable_rollback, dry_run, force):
    '''Create a new Cloud Formation stack from the given Senza definition file'''

    input = definition

    region = get_region(region)
    check_credentials(region)
    args = parse_args(input, region, version, parameter)

    with Action('Generating Cloud Formation template..'):
        data = evaluate(input.copy(), args, force)
        cfjson = json.dumps(data, sort_keys=True, indent=4)

    stack_name = "{0}-{1}".format(input["SenzaInfo"]["StackName"], version)
    if len(stack_name) > 128:
        raise click.UsageError('Stack name "{}" cannot exceed 128 characters. '.format(stack_name) +
                               ' Please choose another name/version.')

    parameters = []
    for name, parameter in data.get("Parameters", {}).items():
        parameters.append([name, getattr(args, name, None)])

    tags = {
        "Name": stack_name,
        "StackName": input["SenzaInfo"]["StackName"],
        "StackVersion": version
    }

    if "OperatorTopicId" in input["SenzaInfo"]:
        topic = input["SenzaInfo"]["OperatorTopicId"]
        topic_arn = resolve_topic_arn(region, topic)
        if not topic_arn:
            raise click.UsageError('SNS topic "{}" does not exist'.format(topic))
        topics = [topic_arn]
    else:
        topics = None

    capabilities = get_required_capabilities(data)

    cf = boto.cloudformation.connect_to_region(region)

    with Action('Creating Cloud Formation stack {}..'.format(stack_name)):
        try:
            if dry_run:
                info('**DRY-RUN** {}'.format(topics))
            else:
                cf.create_stack(stack_name, template_body=cfjson, parameters=parameters, tags=tags,
                                notification_arns=topics, disable_rollback=disable_rollback, capabilities=capabilities)
        except boto.exception.BotoServerError as e:
            if e.error_code == 'AlreadyExistsException':
                raise click.UsageError('Stack {} already exists. Please choose another version.'.format(stack_name))
            else:
                raise
Ejemplo n.º 11
0
def main():
    # parser = argparse.ArgumentParser()
    # parser.add_argument('from')
    # parser.add_argument('to')
    # parser.add_argument('file')
    # args = parser.parse_args()

    hosts_file = Path('/etc/hosts')

    with hosts_file.open() as fd:
        old_contents = fd.read()

    backup_file = hosts_file.with_suffix('.local-cname-backup')
    with backup_file.open('w') as fd:
        fd.write(old_contents)

    try:
        while True:
            entries = []
            cname_file = Path('/etc/cnames')
            with cname_file.open() as fd:
                for line in fd:
                    (cnameFrom, cnameTo) = line.strip().split('=')
                    print('resoving:' + cnameTo)
                    with Action('Resolving {} ..'.format(cnameTo)):
                        results = socket.getaddrinfo(cnameTo,
                                                     80,
                                                     type=socket.SOCK_STREAM)
                        for result in results:
                            family, type, proto, canonname, sockaddr = result
                            if family in (socket.AF_INET, socket.AF_INET6):
                                ip = sockaddr[0]
                                entries.append((cnameFrom, ip))

            info('Current entries:')
            for hostname, ip in entries:
                info('{} -> {}'.format(hostname, ip))

            with Action('Writing {} ..'.format(hosts_file)):
                with hosts_file.open('w') as fd:
                    fd.write(old_contents)
                    fd.write(
                        '#### Start of entries generated by local-cnames\n')
                    for hostname, ip in entries:
                        fd.write('{} {}\n'.format(ip, hostname))

            time.sleep(60)
    except KeyboardInterrupt:
        # ignore, do not print stacktrace
        pass
    finally:
        backup_file.rename(hosts_file)
Ejemplo n.º 12
0
def test_action():
    try:
        with Action('Try and fail..'):
            raise Exception()
    except:
        pass

    with Action('Perform and progress..') as act:
        act.progress()
        act.error('failing..')

    with Action('Perform and progress..') as act:
        act.progress()
        act.warning('warning..')

    with Action('Perform and progress..') as act:
        act.progress()
        act.ok('all fine')

    with Action('Perform and progress..') as act:
        act.progress()

    with Action('Perform, progress and done', ok_msg='DONE') as act:
        act.progress()

    with Action('Perform action new line', nl=True):
        print('In new line!')

    with pytest.raises(SystemExit):
        with Action('Try and fail badly..') as act:
            act.fatal_error('failing..')
Ejemplo n.º 13
0
def edit_etc_hosts(hosts_file, backup_file, args):
    with hosts_file.open() as fd:
        old_contents = fd.read()

    HEADER = '#### Start of entries generated by local-cname'
    if HEADER in old_contents:
        error('{} seems to have already been modified by local-cname.'.format(
            hosts_file))
        info('Remove the local-cname header line from this file to proceed.')
        sys.exit(1)

    with backup_file.open('w') as fd:
        fd.write(old_contents)

    try:
        while True:
            entries = []

            with Action('Resolving {} ..'.format(args.to)):
                results = socket.getaddrinfo(args.to,
                                             80,
                                             type=socket.SOCK_STREAM)
                for result in results:
                    family, type, proto, canonname, sockaddr = result
                    if family in (socket.AF_INET, socket.AF_INET6):
                        ip = sockaddr[0]
                        entries.append((getattr(args, 'from'), ip))

            info('Current entries:')
            for hostname, ip in entries:
                info('{} -> {}'.format(hostname, ip))

            with Action('Writing {} ..'.format(hosts_file)):
                with hosts_file.open('w') as fd:
                    fd.write(old_contents)
                    fd.write('{}\n'.format(HEADER))
                    for hostname, ip in entries:
                        fd.write('{} {}\n'.format(ip, hostname))

            time.sleep(60)
    except KeyboardInterrupt:
        # ignore, do not print stacktrace
        pass
    finally:
        try:
            backup_file.rename(hosts_file)
        except OSError:
            with hosts_file.open('w') as fd:
                fd.write(old_contents)
            os.remove(backup_file)
Ejemplo n.º 14
0
def find_taupage_amis(regions: list) -> dict:
    '''
    Find latest Taupage AMI for each region
    '''
    result = {}
    for region in regions:
        with Action('Finding latest Taupage AMI in {}..'.format(region)):
            ec2 = boto3.resource('ec2', region)
            filters = [{
                'Name': 'name',
                'Values': ['*Taupage-AMI-*']
            }, {
                'Name': 'is-public',
                'Values': ['false']
            }, {
                'Name': 'state',
                'Values': ['available']
            }, {
                'Name': 'root-device-type',
                'Values': ['ebs']
            }]
            images = list(ec2.images.filter(Filters=filters))
            if not images:
                raise Exception('No Taupage AMI found')
            most_recent_image = sorted(images, key=lambda i: i.name)[-1]
            result[region] = most_recent_image
    return result
def launch_instance(region: str, ip: dict, ami: object, subnet: dict,
                    security_group_id: str, is_seed: bool, options: dict):

    node_type = 'SEED' if is_seed else 'NORMAL'
    msg = 'Launching {} node {} in {}..'.format(node_type, ip['_defaultIp'],
                                                region)
    with Action(msg) as act:
        ec2 = boto3.client('ec2', region_name=region)

        mappings = ami.block_device_mappings
        block_devices = override_ephemeral_block_devices(mappings)

        volume_name = '{}-{}'.format(options['cluster_name'], ip['PrivateIp'])
        create_tagged_volume(ec2, options, subnet['AvailabilityZone'],
                             volume_name)

        user_data = options['user_data']
        user_data['volumes']['ebs']['/dev/xvdf'] = volume_name
        taupage_user_data = dump_user_data_for_taupage(user_data)

        resp = ec2.run_instances(
            ImageId=ami.id,
            MinCount=1,
            MaxCount=1,
            SecurityGroupIds=[security_group_id],
            UserData=taupage_user_data,
            InstanceType=options['instance_type'],
            SubnetId=subnet['SubnetId'],
            PrivateIpAddress=ip['PrivateIp'],
            BlockDeviceMappings=block_devices,
            IamInstanceProfile={'Arn': options['instance_profile']['Arn']},
            DisableApiTermination=not (options['no_termination_protection']))
        instance = resp['Instances'][0]
        instance_id = instance['InstanceId']

        ec2.create_tags(Resources=[instance_id],
                        Tags=[{
                            'Key': 'Name',
                            'Value': options['cluster_name']
                        }])
        # wait for instance to initialize before we can assign a
        # public IP address to it or tag the attached volume
        while True:
            resp = ec2.describe_instances(InstanceIds=[instance_id])
            instance = resp['Reservations'][0]['Instances'][0]
            if instance['State']['Name'] != 'pending':
                break
            time.sleep(5)
            act.progress()

        if options['use_dmz']:
            ec2.associate_address(InstanceId=instance_id,
                                  AllocationId=ip['AllocationId'])

        alarm_sns_topic_arn = None
        if options['alarm_topics']:
            alarm_sns_topic_arn = options['alarm_topics'][region]

        create_auto_recovery_alarm(region, options['cluster_name'],
                                   instance_id, alarm_sns_topic_arn)
Ejemplo n.º 16
0
def sli_update(obj, product_name, name, sli_file):
    """Update SLI for a product"""
    client = get_client(obj)

    product = client.product_list(name=product_name)
    if not product:
        fatal_error('Product {} does not exist'.format(product_name))

    product = product[0]

    slis = client.sli_list(product, name)
    if not slis:
        fatal_error('SLI {} does not exist'.format(name))

    with Action('Updating SLI {} for product: {}'.format(name, product_name),
                nl=True) as act:
        sli = json.load(sli_file)

        validate_sli(obj, sli, act)

        if not act.errors:
            sli['uri'] = slis[0]['uri']
            s = client.sli_update(sli)

            print(json.dumps(s, indent=4))
Ejemplo n.º 17
0
def ensure_kubectl():
    kubectl = os.path.join(click.get_app_dir(APP_NAME), 'kubectl')

    if not os.path.exists(kubectl):
        os.makedirs(os.path.dirname(kubectl), exist_ok=True)

        platform = sys.platform  # linux or darwin
        arch = 'amd64'  # FIXME: hardcoded value
        url = KUBECTL_URL_TEMPLATE.format(version=KUBECTL_VERSION,
                                          os=platform,
                                          arch=arch)
        with Action('Downloading {}..'.format(url)) as act:
            response = requests.get(url, stream=True)
            local_file = kubectl + '.download'
            with open(local_file, 'wb') as fd:
                for i, chunk in enumerate(
                        response.iter_content(chunk_size=4096)):
                    if chunk:  # filter out keep-alive new chunks
                        fd.write(chunk)
                        if i % 256 == 0:  # every 1MB
                            act.progress()
            os.chmod(local_file, 0o755)
            os.rename(local_file, kubectl)

    return kubectl
Ejemplo n.º 18
0
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)
Ejemplo n.º 19
0
def init(ctx, configuration_file):
    '''Initialize a new AWS account with Sevenseconds'''

    config = yaml.safe_load(configuration_file)
    region = config.get('region')
    check_credentials(region)

    module = importlib.import_module(
        'hoops.templates.sevenseconds.configuration')
    variables = {}

    #    variables = module.gather_user_variables(variables, region)
    with Action('Generating Sevenseconds configuration...'):
        definition_file = tempfile.NamedTemporaryFile()
        try:
            definition = module.generate_definition(variables)
            definition_file.write(definition.encode('utf-8'))
            definition_file.seek(0, 0)
        finally:
            ctx.invoke(sevenseconds.cli.configure,
                       file=definition_file,
                       account_name_pattern='*',
                       saml_user=None,
                       saml_password=None,
                       dry_run=True)
            definition_file.close()
Ejemplo n.º 20
0
def product_update(obj, name, new_name, new_email, product_group_name):
    """Update product"""
    client = get_client(obj)

    ps = client.product_list(name)
    if not ps:
        fatal_error('Product {} does not exist'.format(name))

    with Action('Updating product: {}'.format(name), nl=True):
        p = ps[0]
        if new_name:
            p['name'] = new_name

        if new_email:
            p['email'] = new_email

        if product_group_name:
            pgs = client.product_group_list(name=product_group_name)
            if not pgs:
                fatal_error('Product group {} does not exist'.format(
                    product_group_name))
            p['product_group_uri'] = pgs[0]['uri']

        p = client.product_update(p)

        print(json.dumps(p, indent=4))
Ejemplo n.º 21
0
def slo_create(obj, product_name, title, description, slo_file):
    """
    Create SLO. If SLO file is used, then --title and --description will be ignored.
    """
    client = get_client(obj)

    product = client.product_list(name=product_name)
    if not product:
        fatal_error('Product {} does not exist'.format(product_name))

    product = product[0]

    with Action('Creating SLO for product: {}'.format(product_name),
                nl=True) as act:
        if slo_file:
            slo = json.load(slo_file)
        else:
            slo = {'title': title, 'description': description}

        validate_slo(slo, act)

        if not act.errors:
            new_slo = client.slo_create(product, slo['title'],
                                        slo.get('description', ''))

            print(json.dumps(new_slo, indent=4))

            for target in slo.get('targets', []):
                t = client.target_create(new_slo,
                                         target['sli_uri'],
                                         target_from=target['from'],
                                         target_to=target['to'])
                act.ok('Created a new target')
                print(json.dumps(t, indent=4))
Ejemplo n.º 22
0
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)))
Ejemplo n.º 23
0
def delete(stack_ref: List[str],
           region: str, dry_run: bool, force: bool, remote: str):
    """Delete Cloud Formation stacks"""
    lizzy = setup_lizzy_client(remote)
    stack_refs = get_stack_refs(stack_ref)
    all_with_version = all(stack.version is not None
                           for stack in stack_refs)

    # this is misleading but it's the current behaviour of senza
    # TODO Lizzy list (stack_refs) to see if it actually matches more than one stack
    # to match senza behaviour
    if (not all_with_version and not dry_run and not force):
        fatal_error(
            'Error: {} matching stacks found. '.format(len(stack_refs)) +
            'Please use the "--force" flag if you really want to delete multiple stacks.')

    # TODO pass force option to agent

    output = ''
    for stack in stack_refs:
        if stack.version is not None:
            stack_id = '{stack.name}-{stack.version}'.format(stack=stack)
        else:
            stack_id = stack.name

        with Action("Requesting stack '{stack_id}' deletion..",
                    stack_id=stack_id):
            output = lizzy.delete(stack_id, region=region, dry_run=dry_run)

    print(output)
Ejemplo n.º 24
0
def init(definition_file, region, template, user_variable):
    '''Initialize a new Senza definition'''
    region = get_region(region)
    check_credentials(region)
    account_info = AccountArguments(region=region)

    templates = []
    for mod in os.listdir(os.path.join(os.path.dirname(__file__),
                                       'templates')):
        if not mod.startswith('_'):
            templates.append(mod.split('.')[0])
    while template not in templates:
        template = choice('Please select the project template',
                          [(t, get_template_description(t))
                           for t in sorted(templates)],
                          default='webapp')

    module = importlib.import_module('senza.templates.{}'.format(template))
    variables = {}
    for key_val in user_variable:
        key, val = key_val
        variables[key] = val
    variables = module.gather_user_variables(variables, region, account_info)
    with Action('Generating Senza definition file {}..'.format(
            definition_file.name)):
        definition = module.generate_definition(variables)
        definition_file.write(definition)
Ejemplo n.º 25
0
def docker_login_with_token(url, access_token):
    '''Configure docker with existing OAuth2 access token'''

    config_paths = list(
        map(os.path.expanduser, ['~/.docker/config.json', '~/.dockercfg']))
    for path in config_paths:
        try:
            with open(path) as fd:
                dockercfg = yaml.safe_load(fd)
            if path.endswith('.dockercfg'):
                dockercfg = {'auths': dockercfg}
        except:
            dockercfg = {}
        if dockercfg:
            break
    basic_auth = codecs.encode(
        'oauth2:{}'.format(access_token).encode('utf-8'),
        'base64').strip().decode('utf-8')
    if 'auths' not in dockercfg:
        dockercfg['auths'] = {}
    dockercfg['auths'][url] = {
        'auth': basic_auth,
        'email': '*****@*****.**'
    }
    for path in config_paths:
        with Action(
                'Storing Docker client configuration in {}..'.format(path)):
            os.makedirs(os.path.dirname(path), exist_ok=True)
            with open(path, 'w') as fd:
                if path.endswith('.dockercfg'):
                    # old config file format
                    json.dump(dockercfg['auths'], fd)
                else:
                    json.dump(dockercfg, fd)
Ejemplo n.º 26
0
def target_update(obj, target_uri, sli_name, target_from, target_to,
                  target_file):
    """Update Target for a product SLO."""
    client = get_client(obj)

    target = client.target_get(target_uri)
    if not target:
        fatal_error('Target {} does not exist'.format(target_uri))

    product = client.product_list(name=target['product_name'])[0]

    sli = client.sli_list(product=product, name=sli_name)
    if not sli:
        fatal_error('SLI {} does not exist'.format(sli_name))
    sli = sli[0]

    with Action('Updating Target {} for product {}'.format(
            target_uri, target['product_name']),
                nl=True) as act:
        if target_file:
            target = json.load(target_file)
        else:
            if sli_name:
                target['sli_uri'] = sli['uri']
            if target_from:
                target['from'] = target_from
            if target_to:
                target['to'] = target_to

        validate_target(target, act)

        if not act.errors:
            target = client.target_update(target)

            print(json.dumps(target, indent=4))
Ejemplo n.º 27
0
def login(obj, profile, refresh, awsprofile):
    '''Login with given profile(s)'''

    repeat = True
    while repeat:
        last_update = get_last_update(obj)
        if 'profile' in last_update and last_update['profile'] and not profile:
            profile = [last_update['profile']]
        for prof in profile:
            if prof not in obj['config']:
                raise click.UsageError('Profile "{}" does not exist'.format(prof))

            login_with_profile(obj, prof, obj['config'][prof], awsprofile)
        if refresh:
            last_update = get_last_update(obj)
            wait_time = 3600 * 0.9
            with Action('Waiting {} minutes before refreshing credentials..'
                        .format(round(((last_update['timestamp']+wait_time)-time.time()) / 60))) as act:
                while time.time() < last_update['timestamp'] + wait_time:
                    try:
                        time.sleep(120)
                    except KeyboardInterrupt:
                        # do not show "EXCEPTION OCCURRED" for CTRL+C
                        repeat = False
                        break
                    act.progress()
        else:
            repeat = False
Ejemplo n.º 28
0
def docker_login_with_token(url, access_token):
    '''Configure docker with existing OAuth2 access token'''

    path = os.path.expanduser('~/.docker/config.json')
    try:
        with open(path) as fd:
            dockercfg = json.load(fd)
    except Exception as e:
        dockercfg = {}
    basic_auth = codecs.encode(
        'oauth2:{}'.format(access_token).encode('utf-8'),
        'base64').strip().decode('utf-8')
    if 'auths' not in dockercfg:
        dockercfg['auths'] = {}
    if 'credsStore' in dockercfg:
        del dockercfg['credsStore']

    dockercfg['auths'][url] = {
        'auth': basic_auth,
        'email': '*****@*****.**'
    }
    with Action('Storing Docker client configuration in {}..'.format(path)):
        os.makedirs(os.path.dirname(path), exist_ok=True)
        with open(path, 'w') as fd:
            json.dump(dockercfg, fd)
Ejemplo n.º 29
0
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('"')))
Ejemplo n.º 30
0
def create(obj, profile_name, url, user):
    '''Create a new profile'''
    if not url.startswith('http'):
        url = 'https://{}'.format(url)

    saml_xml, roles = saml_login(user, url)

    if not roles:
        error('No roles found')
        exit(1)

    if len(roles) == 1:
        role = roles[0]
        if role[2] is None:
            role = (role[0], role[1], profile_name)
    else:
        role = choice('Please select one role', [(r, get_role_label(r)) for r in sorted(roles)])

    data = obj['config']

    if not data:
        data = {}

    data[profile_name] = {
        'saml_identity_provider_url': url,
        'saml_role': role,
        'saml_user': user
    }

    path = obj['config-file']

    with Action('Storing new profile in {}..'.format(path)):
        os.makedirs(obj['config-dir'], exist_ok=True)
        with open(path, 'w') as fd:
            yaml.safe_dump(data, fd)