Example #1
0
class Compute(object):
    """ Light wrapper around libcloud to facilitate integration with strategy files,
        and simplification of commands """

    offset = 0
    node = None
    node_specs = None
    node_name = None
    provider_name = None
    provider_dict = None
    provider_cls = None
    key_pair = None

    def __init__(self, strategy_file):
        self.strategy = Strategy(strategy_file)
        self.set_node()

    def __getattr__(self, attr):
        return getattr(self.provider_cls, attr)

    def set_node(self):
        self.provider_dict = self.strategy.get_provider(self.offset)

        self.provider_cls = (lambda driver: driver(
            region=self.provider_dict['provider']['region'],
            **self.provider_dict['auth']
        ))(get_driver(getattr(Provider, self.provider_dict['provider']['name'])))

        if 'http_proxy' in environ:
            self.provider_cls.connection.set_http_proxy(proxy_url=environ['http_proxy'])

        # pp(map(obj_to_d, self.list_sizes()))
        get_option = partial(self.strategy.get_option,
                             provider_name=self.provider_dict['provider']['name'])

        '''pp(map(node_to_dict,
              ifilter(lambda n: '14.04.5 x64' in n.id or '14.04.5 x64' in n.name, self.list_images())))'''

        self.node_specs = {
            'size': get_option('hardware', self.list_sizes()),
            'image': get_option('image', self.list_images()),
            'location': get_option('location', self.list_locations())
        }

        if 'create_with' in self.provider_dict:
            self.node_specs.update(self.provider_dict['create_with'])

        if 'node_password' in self.provider_dict['ssh']:
            self.node_specs.update({
                'auth': NodeAuthPassword(self.provider_dict['ssh']['node_password'])
            })

        pp({self.provider_dict['provider']['name']: self.node_specs})

        if 'security_group' in self.provider_dict:
            self.node_specs.update({'ex_securitygroup': self.provider_dict['security_group']})
        if 'key_name' in self.provider_dict:
            self.node_specs.update({'ex_keyname': self.provider_dict['key_name']})

        self.node_specs.update(dict((ex, val) for ex, val in self.provider_dict.iteritems() if ex.startswith('ex')))

    def restrategise(self):
        self.offset += 1
        self.set_node()

    def setup_keypair(self):
        try:
            self.import_key_pair_from_file(
                name=self.provider_dict['ssh']['key_name'],
                key_file_path=self.provider_dict['ssh']['public_key_path']
            )
        except NotImplementedError:
            logger.warn(
                '`import_key_pair_from_file` not implemented for {}'.format(self.provider_dict['provider']['name']))
            pass  # DW about it
        except Exception as e:
            if not e.message.startswith('InvalidKeyPair.Duplicate'):
                raise e

    def attempt_provision(self, create_or_deploy='create', prefer_provider=None, prefer_image=None):
        if ping_port() is not True:
            raise EnvironmentError('etcd server not up')

        if prefer_provider:
            self.strategy.strategy['provider']['options'] = (next(
                ifilter(
                    lambda obj: obj.keys()[0] == prefer_provider,
                    self.strategy.strategy['provider']['options']
                )
            ),)
            '''
            # Prefer syntax
            self.strategy.strategy['provider']['options'].insert(
                0, self.strategy.strategy['provider']['options'].pop(
                    next(
                        ifilter(
                            lambda (idx, obj): obj.keys()[0] == prefer_provider,
                            enumerate(self.strategy.strategy['provider']['options'])
                        )
                    )[0]
                )
            )
            '''
        for i in xrange(len(self.strategy.strategy['provider']['options'])):  # Threshold
            logger.info('Attempting to create node "{node_name}" on: {provider}'.format(
                node_name=self.strategy.get_node_name(), provider=self.provider_dict['provider']['name']
            ))
            self.provision(create_or_deploy)

            if self.node:
                save_node_info(self.node_name, node_to_dict(self.node), marshall=json)
                return self.node
            self.restrategise()

        raise LibcloudError('Failed to provision node')

    def provision(self, create_or_deploy):
        try:
            self.setup_keypair()
        except LibcloudError as e:
            logger.warn('{cls}: {msg}'.format(cls=e.__class__.__name__, msg=e.message))

        if 'ex_securitygroup' in self.node_specs and self.provider_dict['provider']['name'].startswith('EC2'):
            print self.node_specs['ex_securitygroup']

        if create_or_deploy == 'deploy':
            with open(self.provider_dict['ssh']['public_key_path'], mode='rt') as f:
                public_ssh_key = f.read()
            self.node_specs.update({'deploy': SSHKeyDeployment(public_ssh_key)})

        self.node_name = self.strategy.get_node_name()
        try:
            self.node = getattr(
                self, '{0}_node'.format(create_or_deploy)
            )(name=self.node_name, **self.node_specs)
        except NotImplementedError as e:
            if create_or_deploy != 'deploy':
                raise e
            error_message = 'deploy_node not implemented for this driver'
            if e.message != error_message:
                raise
            logger.info('{error_message}, so running `create_node` instead.'.format(
                error_message=error_message.replace('deploy_node', '`deploy_node`')
            ))
            self.node = self.create_node(name=self.node_name, **self.node_specs)
            # logger.info('SoftLayer billing is giving error, will remove condition once resolved.')
        except LibcloudError as e:
            logger.warn('{cls}: {msg}'.format(cls=e.__class__.__name__, msg=e.message))
        except Exception as e:
            if e.message.startswith('InvalidGroup.NotFound'):
                print 'InvalidGroup.NotFound'
                exit(1)
            else:
                raise e