<commit_before># -*- coding: utf-8 -*-

"""     
    nubo.clouds.base
    ================

    Support deployments on multiple cloud providers.

    :copyright: (C) 2013 by <NAME>.
"""

import time
import socket
import logging
import hashlib

from importlib import import_module

from os import getenv
from os.path import join

from libcloud.compute.types import Provider, InvalidCredsError
from libcloud.compute.providers import get_driver

from nubo.config import read_config
from nubo.remote import RemoteHost

CLOUDS_MAPPING = {
    'EC2_US_EAST':        'nubo.clouds.ec2.AmazonEC2', 
    'EC2_US_WEST':        'nubo.clouds.ec2.AmazonEC2', 
    'EC2_US_WEST_OREGON': 'nubo.clouds.ec2.AmazonEC2', 
    'EC2_AP_SOUTHEAST':   'nubo.clouds.ec2.AmazonEC2', 
    'EC2_AP_SOUTHEAST2':  'nubo.clouds.ec2.AmazonEC2', 
    'EC2_AP_NORTHEAST':   'nubo.clouds.ec2.AmazonEC2', 
    'EC2_EU_WEST':        'nubo.clouds.ec2.AmazonEC2',
    'RACKSPACE':          'nubo.clouds.rackspace.Rackspace',
    'RACKSPACE_UK':       'nubo.clouds.rackspace.Rackspace',
    'DIGITAL_OCEAN':      'nubo.clouds.digitalocean.DigitalOcean',
    'OPENNEBULA':         'nubo.clouds.opennebula.OpenNebula',
}

NODE_STATES = {
    0: 'RUNNING',
    1: 'REBOOTING',
    2: 'TERMINATED',
    3: 'PENDING',
    4: 'UNKNOWN'
}

AVAILABLE_CLOUDS = read_config()

def node2dict(node):
    """Convert a node object into a dict"""
    fields = ( 'id', 'name', 'state', 'public_ips', 
               'private_ips', 'image', 'size', 'extra' )
    values = {}
    for field in fields:
        value = getattr(node, field)
        if value is not None:
            values[field] = value

    values['state'] = NODE_STATES[values['state']]

    for field in 'image', 'size':
        if 'field' in values and values[field]:
            values[field] = values[field].name

    for field in 'public_ips', 'private_ips':
        try:
            values[field] = [ ip_addr.address for ip_addr in values[field] ]
        except AttributeError:
            pass

    return values

def supported_clouds():
    return CLOUDS_MAPPING.keys()

def get_cloud(cloud_name):
    """Return a class representing the given cloud provider.

    eg: get_cloud(cloud_name='EC2_US_WEST_OREGON') 
            -> <class 'nubo.clouds.ec2.AmazonEC2'>
    """
    # fullname = [ 'nubo', 'clouds', 'ec2', 'EC2Cloud' ]
    fullname = CLOUDS_MAPPING[cloud_name].split('.')

    # classname = 'EC2Cloud'
    classname = fullname.pop()

    # module_name = 'nubo.clouds.ec2'
    module_name = '.'.join(fullname)

    module = import_module(module_name)

    cloudclass = getattr(module, classname)
    cloudclass.PROVIDER_NAME = cloud_name

    return cloudclass

class BaseCloud(object):

    # Wait a maximum of 5 minutes
    MAX_ATTEMPTS = 5 * 60
   
    # Has to be set by extending classes
    PROVIDER_NAME = None

    # Can be extended
    NEEDED_PARAMS = [ 'key', 'secret' ]

    @classmethod
    def test_conn(cls, **params):
        provider = getattr(Provider, cls.PROVIDER_NAME)
        DriverClass = get_driver(provider)
        driver = DriverClass(**params)
        try:
            return type(driver.list_nodes()) == list
        except InvalidCredsError:
            return False

    def __init__(self, ssh_private_key=None, login_as='root'):
        if ssh_private_key is None:
            ssh_private_key = join(getenv('HOME'), '.ssh', 'id_rsa')

        self.ssh_private_key = ssh_private_key
        self.ssh_public_key = ssh_private_key + '.pub'

        # Use public key's MD5 sum as its name
        key_hash = hashlib.md5()
        key_hash.update(open(self.ssh_public_key).read())
        self.ssh_key_name = key_hash.hexdigest()
        
        self.login_as = login_as

        try:
            provider = getattr(Provider, self.PROVIDER_NAME)
        except AttributeError:
            raise Exception, "Unknown cloud %s" % PROVIDER_NAME

        DriverClass = get_driver(provider)
        self.driver = DriverClass(
            **AVAILABLE_CLOUDS[CLOUDS_MAPPING[self.PROVIDER_NAME]])

    def __wait_for_node(self, node_id):
        attempts = self.MAX_ATTEMPTS

        while attempts:
            for node in self.list_nodes():
                if node['id'] != node_id: 
                    continue

                if node['state'] == "RUNNING":
                    return node
                
                logging.info("%s attempts left on %s: %s != RUNNING" % (
                    attempts, node_id, node['state']))
            
            time.sleep(1)
            attempts -= 1

    def __wait_for_ssh(self, node):
        attempts = self.MAX_ATTEMPTS
        remotehost = RemoteHost(node['public_ips'][0], self.ssh_private_key)

        while attempts:
            try:
                return remotehost.whoami(self.login_as)
            except socket.error:
                logging.info("%s SSH attempts left for user %s on %s" <commit_msg>Fix exception message when trying to use unknown cloud providers<commit_after># -*- coding: utf-8 -*-

"""     
    nubo.clouds.base
    ================

    Support deployments on multiple cloud providers.

    :copyright: (C) 2013 by <NAME>.
"""

import time
import socket
import logging
import hashlib

from importlib import import_module

from os import getenv
from os.path import join

from libcloud.compute.types import Provider, InvalidCredsError
from libcloud.compute.providers import get_driver

from nubo.config import read_config
from nubo.remote import RemoteHost

CLOUDS_MAPPING = {
    'EC2_US_EAST':        'nubo.clouds.ec2.AmazonEC2', 
    'EC2_US_WEST':        'nubo.clouds.ec2.AmazonEC2', 
    'EC2_US_WEST_OREGON': 'nubo.clouds.ec2.AmazonEC2', 
    'EC2_AP_SOUTHEAST':   'nubo.clouds.ec2.AmazonEC2', 
    'EC2_AP_SOUTHEAST2':  'nubo.clouds.ec2.AmazonEC2', 
    'EC2_AP_NORTHEAST':   'nubo.clouds.ec2.AmazonEC2', 
    'EC2_EU_WEST':        'nubo.clouds.ec2.AmazonEC2',
    'RACKSPACE':          'nubo.clouds.rackspace.Rackspace',
    'RACKSPACE_UK':       'nubo.clouds.rackspace.Rackspace',
    'DIGITAL_OCEAN':      'nubo.clouds.digitalocean.DigitalOcean',
    'OPENNEBULA':         'nubo.clouds.opennebula.OpenNebula',
}

NODE_STATES = {
    0: 'RUNNING',
    1: 'REBOOTING',
    2: 'TERMINATED',
    3: 'PENDING',
    4: 'UNKNOWN'
}

AVAILABLE_CLOUDS = read_config()

def node2dict(node):
    """Convert a node object into a dict"""
    fields = ( 'id', 'name', 'state', 'public_ips', 
               'private_ips', 'image', 'size', 'extra' )
    values = {}
    for field in fields:
        value = getattr(node, field)
        if value is not None:
            values[field] = value

    values['state'] = NODE_STATES[values['state']]

    for field in 'image', 'size':
        if 'field' in values and values[field]:
            values[field] = values[field].name

    for field in 'public_ips', 'private_ips':
        try:
            values[field] = [ ip_addr.address for ip_addr in values[field] ]
        except AttributeError:
            pass

    return values

def supported_clouds():
    return CLOUDS_MAPPING.keys()

def get_cloud(cloud_name):
    """Return a class representing the given cloud provider.

    eg: get_cloud(cloud_name='EC2_US_WEST_OREGON') 
            -> <class 'nubo.clouds.ec2.AmazonEC2'>
    """
    # fullname = [ 'nubo', 'clouds', 'ec2', 'EC2Cloud' ]
    fullname = CLOUDS_MAPPING[cloud_name].split('.')

    # classname = 'EC2Cloud'
    classname = fullname.pop()

    # module_name = 'nubo.clouds.ec2'
    module_name = '.'.join(fullname)

    module = import_module(module_name)

    cloudclass = getattr(module, classname)
    cloudclass.PROVIDER_NAME = cloud_name

    return cloudclass

class BaseCloud(object):

    # Wait a maximum of 5 minutes
    MAX_ATTEMPTS = 5 * 60
   
    # Has to be set by extending classes
    PROVIDER_NAME = None

    # Can be extended
    NEEDED_PARAMS = [ 'key', 'secret' ]

    @classmethod
    def test_conn(cls, **params):
        provider = getattr(Provider, cls.PROVIDER_NAME)
        DriverClass = get_driver(provider)
        driver = DriverClass(**params)
        try:
            return type(driver.list_nodes()) == list
        except InvalidCredsError:
            return False

    def __init__(self, ssh_private_key=None, login_as='root'):
        if ssh_private_key is None:
            ssh_private_key = join(getenv('HOME'), '.ssh', 'id_rsa')

        self.ssh_private_key = ssh_private_key
        self.ssh_public_key = ssh_private_key + '.pub'

        # Use public key's MD5 sum as its name
        key_hash = hashlib.md5()
        key_hash.update(open(self.ssh_public_key).read())
        self.ssh_key_name = key_hash.hexdigest()
        
        self.login_as = login_as

        try:
            provider = getattr(Provider, self.PROVIDER_NAME)
        except AttributeError:
            raise Exception, "Unknown cloud %s" % self.PROVIDER_NAME

        DriverClass = get_driver(provider)
        self.driver = DriverClass(
            **AVAILABLE_CLOUDS[CLOUDS_MAPPING[self.PROVIDER_NAME]])

    def __wait_for_node(self, node_id):
        attempts = self.MAX_ATTEMPTS

        while attempts:
            for node in self.list_nodes():
                if node['id'] != node_id: 
                    continue

                if node['state'] == "RUNNING":
                    return node
                
                logging.info("%s attempts left on %s: %s != RUNNING" % (
                    attempts, node_id, node['state']))
            
            time.sleep(1)
            attempts -= 1

    def __wait_for_ssh(self, node):
        attempts = self.MAX_ATTEMPTS
        remotehost = RemoteHost(node['public_ips'][0], self.ssh_private_key)

        while attempts:
            try:
                return remotehost.whoami(self.login_as)
            except socket.error:
                logging.info("%s SSH attempts left for user %s on %s" 
{'fraction_non_alphanumeric': 0.11445051608986036, 'fraction_numerical': 0.009917020845982595, 'mean_word_length': 2.428026361429067, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2087178', 'n_tokens_mistral': 3384, 'n_tokens_neox': 3229, 'n_words': 701}