from cloudmesh_client.cloud.network import Network
from cloudmesh_client.cloud.image import Image
from cloudmesh_client.cloud.vm import Vm
from cloudmesh_client import Console
from cloudmesh_client.api import Resource, Provider, Node
from cloudmesh_client.db.openstack.model import IMAGE_OPENSTACK, VM_OPENSTACK
from cloudmesh_client.common.util import exponential_backoff
from cloudmesh_client.default import Default
[docs]class ImageResource(Resource):
[docs]    def refresh(self):
        pass  
[docs]class KeyResource(Resource):
    pass 
[docs]class FloatingIpResource(Resource):
    pass 
[docs]class FlavorResource(Resource):
    pass 
[docs]class OpenstackProvider(Provider):
    # def __init__(self):
    #     super(OpenstackProvider, self).__init__()
    #
    #     self.images = ImageResource()
    #     self._add_resource(self.images)
    #
    #     self.keys = KeyResource()
    #     self._add_resource(self.keys)
    #
    #     self.flavors = FlavorResource()
    #     self._add_resource(self.flavors)
    #
    #     self.floating_ips = FloatingIpResource()
    #     self._add_resource(self.floating_ips)
[docs]    def boot(self, **kwargs):
        """Boot a single VM
        :param kwargs: parameters to :meth:`Vm.boot`
        :return: the vm details
        :rtype: :class:`Node`
        """
        cloud = kwargs.get('cloud', Default.cloud)
        name = kwargs.get('name', Vm.generate_vm_name())
        image = kwargs.get('image', Default.image)
        flavor = kwargs.get('flavor', Default.flavor)
        key = kwargs.get('key', Default.key)
        secgroup = kwargs.get('secgroup', Default.secgroup)
        group = kwargs.get('group', Default.group)
        username = kwargs.get('username', Image.guess_username(image))
        cluster = kwargs.get('cluster', None)
        # shorthand for getting a dict of all the vm details
        #
        # IMPORTANT: anything declared prior to the call to `locals()`
        # may be passed to `Vm.boot`, so make sure that only parameters are
        # defined above this comment.
        details = locals()
        details.pop('kwargs')
        # currently, Vm.boot returns the instance UUID from the provider for openstack images
        # 2016/12/12
        uuid = Vm.boot(**details)
        # helper function: the Vm.boot only returns a UUID, but we
        # need to use the VM model instead. Additionally, we'll need
        # to poll the VM to wait until it is active.
        #
        # The kwargs are used to select the item from the DB:
        # eg: uuid=???, cm_id=???, etc
        def get_vm(**kwargs):
            """Selects the VM based on the given properties"""
            model = self.db.vm_table_from_provider('openstack')
            vm = self.db.select(model, **kwargs).all()
            assert len(vm) == 1, vm
            vm = vm[0]
            return vm
        # get the VM from the UUID
        vm = get_vm(uuid=uuid)
        cm_id = vm.cm_id
        def is_active():
            Vm.refresh(cloud=cloud)
            vm = get_vm(cm_id=cm_id)
            return vm.status == 'ACTIVE'
        if not exponential_backoff(is_active):
            Console.error('Failed to get ACTIVE vm within timeframe')
            raise ValueError
        assert is_active()
        vm = get_vm(cm_id=cm_id)
        assert isinstance(vm, VM_OPENSTACK), vm.__class__
        return OpenstackNode(model=vm, provider=self) 
[docs]    def create_ip(self, node):
        ip = Network.find_assign_floating_ip(
            cloudname=self.cloud,
            instance_id=node.name,
        )
        Vm.refresh(cloud=self.cloud)
        Console.ok('Assigned ip to {}: {}'.format(node.name, ip)) 
[docs]    def delete(self, nodde):
        raise NotImplementedError 
[docs]    def node(self):
        raise NotImplementedError  
[docs]class OpenstackNode(Node):
    def __init__(self, model, provider):
        super(Node, self).__init__()
        self._model = model
        self._provider = provider
    @property
    def name(self):
        return self._model.name
    @property
    def username(self):
        return self._model.username
    @property
    def private_ip(self):
        return self.model.static_ip
    @property
    def public_ip(self):
        return self.model.floating_ip
[docs]    def boot(self, **kwargs):
        pass 
[docs]    def delete(self):
        raise NotImplementedError 
[docs]    def start(self):
        raise NotImplementedError 
[docs]    def stop(self):
        raise NotImplementedError 
[docs]    def ssh(self, cmd=None, user=None):
        raise NotImplementedError 
[docs]    def create_ip(self):
        self._provider.create_ip(self)