2853: Merge branch 'master' into 2853-rendezvous
[arvados.git] / services / nodemanager / arvnodeman / computenode / driver / __init__.py
1 #!/usr/bin/env python
2
3 from __future__ import absolute_import, print_function
4
5 class BaseComputeNodeDriver(object):
6     """Abstract base class for compute node drivers.
7
8     libcloud abstracts away many of the differences between cloud providers,
9     but managing compute nodes requires some cloud-specific features (e.g.,
10     on EC2 we use tags to identify compute nodes).  Compute node drivers
11     are responsible for translating the node manager's cloud requests to a
12     specific cloud's vocabulary.
13
14     Subclasses must implement arvados_create_kwargs (to update node
15     creation kwargs with information about the specific Arvados node
16     record), sync_node, and node_start_time.
17     """
18     def __init__(self, auth_kwargs, list_kwargs, create_kwargs, driver_class):
19         self.real = driver_class(**auth_kwargs)
20         self.list_kwargs = list_kwargs
21         self.create_kwargs = create_kwargs
22
23     def __getattr__(self, name):
24         # Proxy non-extension methods to the real driver.
25         if (not name.startswith('_') and not name.startswith('ex_')
26               and hasattr(self.real, name)):
27             return getattr(self.real, name)
28         else:
29             return super(BaseComputeNodeDriver, self).__getattr__(name)
30
31     def search_for(self, term, list_method, key=lambda item: item.id):
32         cache_key = (list_method, term)
33         if cache_key not in self.SEARCH_CACHE:
34             results = [item for item in getattr(self.real, list_method)()
35                        if key(item) == term]
36             count = len(results)
37             if count != 1:
38                 raise ValueError("{} returned {} results for '{}'".format(
39                         list_method, count, term))
40             self.SEARCH_CACHE[cache_key] = results[0]
41         return self.SEARCH_CACHE[cache_key]
42
43     def list_nodes(self):
44         return self.real.list_nodes(**self.list_kwargs)
45
46     def arvados_create_kwargs(self, arvados_node):
47         raise NotImplementedError("BaseComputeNodeDriver.arvados_create_kwargs")
48
49     def create_node(self, size, arvados_node):
50         kwargs = self.create_kwargs.copy()
51         kwargs.update(self.arvados_create_kwargs(arvados_node))
52         kwargs['size'] = size
53         return self.real.create_node(**kwargs)
54
55     def sync_node(self, cloud_node, arvados_node):
56         # When a compute node first pings the API server, the API server
57         # will automatically assign some attributes on the corresponding
58         # node record, like hostname.  This method should propagate that
59         # information back to the cloud node appropriately.
60         raise NotImplementedError("BaseComputeNodeDriver.sync_node")
61
62     @classmethod
63     def node_start_time(cls, node):
64         raise NotImplementedError("BaseComputeNodeDriver.node_start_time")