def handle(event, _context):
    """Lambda Handler"""
    log_event(event)

    # If you're using a self signed certificate change
    # the ssl_verify argument to False
    with chef.ChefAPI(CHEF_SERVER_URL,
                      get_pem(),
                      USERNAME,
                      ssl_verify=VERIFY_SSL):
        instance_id = get_instance_id(event)
        try:
            search = chef.Search('node', 'ec2_instance_id:' + instance_id)
        except ChefServerNotFoundError as err:
            LOGGER.error(err)
            return False

        if len(search) != 0:
            for instance in search:
                node = chef.Node(instance.object.name)
                client = chef.Client(instance.object.name)
                try:
                    node.delete()
                    LOGGER.info('===Node Delete: SUCCESS===')
                    client.delete()
                    LOGGER.info('===Client Delete: SUCCESS===')
                    return True
                except ChefServerNotFoundError as err:
                    LOGGER.error(err)
                    return False
        else:
            LOGGER.info(
                '=Instance does not appear to be Chef Server managed.=')
            return True
Example #2
0
def search_pick_node(search_query, api):
    """
        Perform node search for `search_query` with `api`,
        lets the user pick interactivly if there are multiple nodes returned
        Throws LookupError if can't find a matching node
    """
    nodes = [node for node in chef.Search('node', search_query, api=api)]
    node = None

    # no nodes match the search
    if not nodes:
        raise exceptions.LookupError("Can't find a node matching %s" % (search_query,))
    # more than one node matched the search. let the user choose one
    elif len(nodes) > 1:
        # sort the results before displaying them
        nodes.sort(lambda a,b: cmp(a.object.name.lower(), b.object.name.lower()))

        print '%d nodes matched your query:' % (len(nodes),)
        for i, current_node in enumerate(nodes):
            print "\t%d. %s" % (i+1, current_node.object.name,)

        while not node:
            selected_node = raw_input('Please select one: ')
            if not selected_node.isdigit() or not 1 <= int(selected_node) <= len(nodes):
                print 'Invalid selection. Please choose a number between 1 and %d' % (len(nodes),)
            else:
                node = nodes[int(selected_node) - 1]
                print
    # only one result. that's our node.
    else:
        node = nodes[0]

    return node
Example #3
0
    def check_cluster_health(self, callback_url):
        import chef

        cluster_name = self.config_manager.get_clustername()
        nodes = chef.Search(
            'node',
            'tags:rally_node AND name:*%s' % cluster_name,
            api=self.chef_api
        )
        if not nodes:
            err_msg = "Cannot find Rally node!"
            logging.info(err_msg)
            raise Exception(err_msg)

        rally_node_name = None
        for node in nodes:
            rally_node_name = node.object.name
            break

        rally_node = chef.Node(rally_node_name, api=self.chef_api)
        rally_node_ip = rally_node['ipaddress']

        command = self.config_manager.get_adapter_health_check_cmd()
        command = command.replace('$cluster_name', cluster_name)
        option = '--url %s --clustername %s' % (callback_url, cluster_name)
        command = ' '.join((command, option))

        username, pwd = self.config_manager.get_server_credentials()
        util.execute_cli_by_ssh(
            command, rally_node_ip, username=username,
            password=pwd, nowait=True
        )
Example #4
0
 def refresh_cache(self):
     print("REFRESHING CACHE - COULD TAKE A WHILE", file=sys.stderr)
     with self.api:
         data = {}
         nodes = chef.Search("node")
         for n in nodes:
             data[n["name"]] = n
         self.write_cache(data)
Example #5
0
    def _list_all_nodes(self):
        resp = dict()
        with self.api:
            environments = [e[u'name'] for e in chef.Search(u'environment')]
            nodes = chef.Search(u'node')
            for env in environments:
                apis = u'{}_api'.format(env)
                workers = u'{}_worker'.format(env)
                dbs = u'{}_db'.format(env)
                queues = u'{}_queues'.format(env)
                repose = u'{}_repose'.format(env)

                resp[env] = {u'children': [apis, workers, dbs, queues, repose]}
                resp[apis] = [n[u'automatic'][u'ipaddress'] for n in nodes if (
                    n[u'chef_environment'] == env and \
                    u'roles' in n[u'automatic'].keys() and \
                    u'barbican-api' in n[u'automatic'][u'roles']
                )]
                resp[workers] = [n[u'automatic'][u'ipaddress'] for n in nodes \
                    if (
                        n[u'chef_environment'] == env and \
                        u'roles' in n[u'automatic'].keys() and \
                        u'barbican-worker' in n[u'automatic'][u'roles']
                    )
                ]
                resp[dbs] = [n[u'automatic'][u'ipaddress'] for n in nodes if (
                    n[u'chef_environment'] == env and \
                    u'roles' in n[u'automatic'].keys() and \
                    u'barbican-db' in n[u'automatic'][u'roles']
                )]
                resp[queues] = [n[u'automatic'][u'ipaddress'] for n in nodes \
                    if (
                        n[u'chef_environment'] == env and \
                        u'roles' in n[u'automatic'].keys() and \
                        u'barbican-queue' in n[u'automatic'][u'roles']
                    )
                ]
                resp[repose] = [n[u'automatic'][u'ipaddress'] for n in nodes \
                    if (
                        n[u'chef_environment'] == env and \
                        u'roles' in n[u'automatic'].keys() and \
                        u'barbican-repose' in n[u'automatic'][u'roles']
                    )
                ]
        print(json.dumps(resp))
Example #6
0
def env(env):
	if env == BOOTSTRAP_ENV:
		flask.abort(400)
	
	if len(chef.Search('environment', 'name:' + env, api = api)) == 0:
		flask.abort(404)

	nodes = list(chef.Search('node', 'chef_environment:%s' % env, api = api))
	nodes.sort(key = lambda n: n.object.name)

	status, output, converging = get_env_status(env, (n.object.name for n in nodes), progress_status = 'converging')

	return flask.render_template(
		'env.html',
		env = env,
		converging = converging,
		status = status,
		output = output,
		nodes = nodes,
	)
Example #7
0
def role_validator(data):
    result = True
    for key in data:
        if key.find('role') == 0:
            role_name = key[key.find('[') + 1:-1]
            if len(chef.Search('role', 'name:%s' % role_name)) == 0:
                logger.error(
                    "Role '%s' does not exist on chef server. Skipping node" %
                    role_name)
                result = False
                break
    return result
Example #8
0
def lambda_handler(event, context):
    print("Event received: " + json.dumps(event))
    for record in event['Records']:
        if 'Sns' in record:
            message = json.loads(record['Sns']['Message'])
            if message['Event'] == 'autoscaling:EC2_INSTANCE_TERMINATE':
                instance_id = message['EC2InstanceId']
                print("instance_id = " + instance_id)

                try:
                    chef_api = chef.autoconfigure()
                except:
                    raise Exception('Could not configure Chef!')

                try:
                    rows = chef.Search('node',
                                       'ec2_instance_id:' + instance_id)
                except:
                    raise Exception(
                        'Could not search for nodes with ec2_instance_id: ' +
                        instance_id)

                for row in rows:
                    try:
                        n = chef.Node(row['name'])
                    except:
                        raise Exception('Could not fetch node object for ' +
                                        row['name'])

                    print("node:   " + str(n))

                    try:
                        c = chef.Client(row['name'])
                    except:
                        raise Exception('Could not fetch client object for ' +
                                        row['name'])

                    print("client: " + str(c))

                    try:
                        n.delete()
                    except:
                        raise Exception('Could not delete node ' + str(n))

                    try:
                        c.delete()
                    except:
                        raise Exception('Could not delete client ' + str(n))

            else:
                raise Exception('Could not process SNS message')
Example #9
0
def handle(event, _context):
    """Lambda Handler"""
    log_event(event)

    #Suppress InsecureRequestWarning: Unverified HTTPS request is being made in Python2.6
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

    # If you're using a self signed certificate change
    # the ssl_verify argument to False
    with chef.ChefAPI(CHEF_SERVER_URL,
                      get_pem(),
                      USERNAME,
                      ssl_verify=VERIFY_SSL):
        instance_id = get_instance_id(event)
        try:
            search = chef.Search('node', 'ec2_instance_id:' + instance_id)
        except ChefServerNotFoundError as err:
            LOGGER.error(err)
            return False

        if len(search) != 0:
            for instance in search:
                node = chef.Node(instance.object.name)
                client = chef.Client(instance.object.name)
                try:
                    LOGGER.info('About to delete the node named - ' +
                                node.name)
                    LOGGER.info('About to delete the client named - ' +
                                client.name)
                    if not DEBUG:
                        node.delete()
                        LOGGER.info('===Node Delete: SUCCESS===')
                        client.delete()
                        LOGGER.info('===Client Delete: SUCCESS===')
                    else:
                        LOGGER.info('Would have deleted the node named - ' +
                                    node.name +
                                    ' here, but we are in DEBUG mode')
                        LOGGER.info('Would have deleted the client named - ' +
                                    client.name +
                                    ' here, but we are in DEBUG mode')
                    return True
                except ChefServerNotFoundError as err:
                    LOGGER.error(err)
                    return False
        else:
            LOGGER.info(
                '=Instance does not appear to be Chef Server managed.=')
            return True
Example #10
0
def process_virtual(chefapi,
                    data,
                    config_file,
                    internal_dns_suffix,
                    force_update=False):

    assign_dict = {}

    # find all internal nodes
    internal_nodes = chef.Search('node',
                                 'role:%s' % INTERNAL_NODE_ROLE,
                                 api=chefapi)

    nodes = itertools.cycle(list(internal_nodes))

    # walk all virtual machines, slotting them to internal_nodes
    for machine in data['virtual']:

        node_to_assign = nodes.next()
        node_name = node_to_assign['name']
        logger.info("Assigning virtual machine '%s' to node %s'" %
                    (machine['name'], node_name))

        if not assign_dict.has_key(node_name):
            assign_dict[node_name] = []

        assign_dict[node_name].append(machine)

        # create chef entry for the virtual machine itself
        virtual_name = machine['name'] + '.' + internal_dns_suffix
        chef_node_obj = chef.Node(name=virtual_name, api=chefapi)
        chef_node_obj.run_list = machine['chef']['run_list']
        chef_node_obj.save()

    for node in assign_dict:

        attrib_dict = {
            'internal-node': {
                'virtual_machines': assign_dict[node]
            }
        }

        chef_node_obj = chef.Node(name=node, api=chefapi)
        chef_node_obj.normal.update(attrib_dict)
        chef_node_obj.save()
Example #11
0
def bootstrap(ip):
	if not bootstrap_enabled or not app.config.get('ENABLE_BOOTSTRAP'):
		flask.abort(400)

	if len(processes(BOOTSTRAP_ENV, ip, only_executing = True)) > 0:
		return ujson.encode({ 'status': 'bootstrapping' })

	if len(chef.Search('node', 'ipaddress:%s OR fqdn:%s OR hostname:%s' % (ip, ip, ip), api = api)) > 0:
		broadcast(BOOTSTRAP_ENV, { 'host': ip, 'status': 'ready', 'data': 'A node already exists at this address.\n' })
		return ujson.encode({ 'status': 'ready' })

	get_command = lambda ip: ['knife', 'bootstrap', '--sudo', ip]

	return _run(
		{ ip: ip, },
		get_command,
		env = BOOTSTRAP_ENV,
		progress_status = 'bootstrapping',
	)
Example #12
0
 def chef_nodes(self):
     """Generator method that queries the chef server and yields node dictionaries."""
     q = 'name:*'
     size = 1000
     start = 0
     while start is not None:
         response = chef.Search('node',
                                q,
                                rows=size,
                                start=start,
                                api=self.api)
         count = 0
         for node in response:
             count += 1
             yield node
         if count == 0 or count < size:
             start = None
         else:
             start += size
Example #13
0
    def get(self, host):
        """Add <host> to device class in POD for monitoring"""
        deviceclass = self.get_argument('deviceclass',
                                        default='/Server/SSH/Linux/Collector')
        #productionState wants an int Prod=1000,PreProd=500,Maint=300,Test=0,Decom=-1
        prodstate = str(self.get_argument('prodstate', default="500"))
        chefapi = chef.autoconfigure()
        master = chef.Node(chefapi.client)
        vpcid = master['vpc_id']
        privip = master['private_ips'][0]
        stackname = master['cluster']['name']
        collectors = master['zenoss']['collector-passwords']
        zaasdomain = master['zaas']['domain']

        for c in collectors:
            if c['collector'] == host:
                #devicename = c['ip']
                devicename = host + '.' + stackname + '.internal.' + zaasdomain

        pod = chef.Search('node', 'hostname:POD* AND vpc_id:' + vpcid)
        podip = pod[0]['automatic']['ipaddress']
        password = pod[0]['normal']['zenoss']['password']
        user = '******'
        url = 'https://' + podip + '/zport/dmd/device_router'
        data = '{"action":"DeviceRouter","method":"addDevice","data":[{"deviceName":"' + devicename + '","deviceClass":"' + deviceclass + '","collector":"localhost","title":"' + host + '","productionState":"' + prodstate + '"}],"tid":1}'
        userpass = user + ":" + password
        auth = "Basic " + userpass.encode("base64").rstrip()
        headers = {
            "Authorization": auth,
            "Content-Type": "application/json; charset=utf-8"
        }

        request = tornado.httpclient.HTTPRequest(url=url,
                                                 method='POST',
                                                 body=data,
                                                 headers=headers,
                                                 validate_cert=False)

        client = tornado.httpclient.AsyncHTTPClient()
        response = yield tornado.gen.Task(client.fetch, request)
        self.finish(response.body)
Example #14
0
def converge(env, node = None):

	if env == BOOTSTRAP_ENV:
		flask.abort(400)

	if len(processes(env, node, only_executing = True)) > 0:
		return ujson.encode({ 'status': 'converging' })

	if node is not None:
		nodes = { node: chef.Node(node, api = api), }
	else:
		nodes = { row.object.name: row.object for row in chef.Search('node', 'chef_environment:' + env, api = api) }
	
	get_command = lambda n: ['ssh', '-o', 'StrictHostKeyChecking=no', n['ipaddress'], 'sudo', 'chef-client']

	return _run(
		nodes,
		get_command,
		env = env,
		progress_status = 'converging',
	)
Example #15
0
def deploy(ctx, env_id, env_config_json=None):
    """Deploy project to AWS."""

    # get target deployment environment configuration
    if env_config_json is not None:
        print("using provided target deployment environment configuration...")
        env_config = json.loads(env_config_json)
    else:
        print("loading target deployment environment configuration...")
        with open('envs-config.json') as envs_config_file:
            env_config = json.load(envs_config_file)[env_id]

    # get AWS account id
    print("getting AWS account id...")
    aws_account_id = boto3.client('sts').get_caller_identity()['Account']

    # get shared resources stack outputs
    print("getting shared AWS resources stack outputs...")
    cloudformation = boto3.client('cloudformation',
                                  region_name=env_config['region'])
    res = cloudformation.describe_stacks(StackName=f'etl-pm-shared-{env_id}')
    aws_resources = {
        **{
            v['OutputKey']: v['OutputValue']
            for v in res['Stacks'][0]['Outputs']
        }
    }

    # deploy CDK app
    print("deploying AWS resources...")
    ctx.run(
        (f'cdk deploy'
         f' --role-arn arn:aws:iam::{aws_account_id}:role/IAS-CloudFormation-Deploy-Role'
         f' --require-approval never'),
        env={
            'CDK_DEPLOY_ENV': env_id,
            'CDK_DEPLOY_REGION': env_config['region'],
            'CDK_DEPLOY_ENV_CONFIG': json.dumps(env_config)
        })

    # get backend resources stack outputs
    print("getting backend AWS resources stack outputs...")
    res = cloudformation.describe_stacks(StackName=f'{APP_NAME}-{env_id}')
    aws_resources.update({
        **{
            v['OutputKey']: v['OutputValue']
            for v in res['Stacks'][0]['Outputs']
        }
    })

    # prepare EMR assets package
    print("assembling EMR assets package...")
    with ctx.cd('emr'):
        ctx.run(
            'rm -rf ../build/assets/emr'
            ' && mkdir -p ../build/assets/emr'
            ' && cp *.py ../build/assets/emr'
            ' && zip -r ../build/assets/emr/packages.zip $(ls -d */) -i \\*.py'
        )

    # upload assets to S3
    print("uploading assets to S3...")
    with open('version.properties') as version_file:
        deployment_version = [
            v.rstrip().split('=')[1] for v in version_file
            if v.startswith('version=')
        ][0]
    region_designator = ''.join(part[0]
                                for part in env_config['region'].split('-'))
    ctx.run(
        f'aws s3 sync --delete build/assets/'
        f' s3://iasrf-vcs-mixed-{region_designator}-de-{env_id}/pm/airflow/{APP_NAME}/v{deployment_version}/'
    )

    # prepare DAGs package
    print("assembling DAGs package...")
    ctx.run(
        f'mkdir -p build/airflow'
        f' && rm -f build/airflow/{APP_NAME}-{env_id}.zip'
        f' && zip -r build/airflow/{APP_NAME}-{env_id}.zip pipeline.py dags -i \\*.py'
    )
    env_config['env_id'] = env_id
    env_config['deployment_version'] = deployment_version
    env_config['alarms_topic_name'] = aws_resources['AlarmsTopicName']
    env_config['notifications_topic_name'] = aws_resources[
        'NotificationsTopicName']
    env_config['jas_bucket_name'] = aws_resources['DataLakeJASBucketName']
    env_config['jas_bucket_data_prefix'] = aws_resources[
        'DataLakeJASBucketDataPrefix']
    env_config['jas_mart_bucket_name'] = aws_resources[
        'DataLakeMartBucketName']
    env_config['jas_mart_bucket_data_prefix'] = aws_resources[
        'DataLakeMartBucketDataPrefix']
    env_config['itermediate_bucket_name'] = aws_resources[
        'IntermediateBucketName']
    env_config['pipeline_state_table_name'] = aws_resources[
        'PipelineStateTableName']
    with open('build/airflow/env-config.json', 'w') as env_config_file:
        json.dump(env_config, env_config_file, indent=2)
    with ctx.cd('build/airflow'):
        ctx.run(f'zip -g {APP_NAME}-{env_id}.zip env-config.json')

    # get Airflow nodes
    print("getting Airflow nodes from Chef...")
    with chef.ChefAPI(CHEF_API_URL, os.environ['CHEF_API_KEY'], CHEF_API_USER):
        airflow_nodes = [
            node.object.name for node in chef.Search(
                'node', f"tags:{env_config['airflow_cluster_id']}.{env_id}")
        ]
    print(f"got Airflow nodes: {airflow_nodes}")

    # upload the DAGs package to Airflow nodes
    for node in airflow_nodes:
        print(f"deploying DAGs package to {node}...")
        ctx.run(
            f'scp -o StrictHostKeyChecking=no build/airflow/{APP_NAME}-{env_id}.zip'
            f' {AIRFLOW_SSH_USER}@{node}:/var/lib/airflow/dags/')