Skip to content

Commit

Permalink
Nodes now have a created_at attribute
Browse files Browse the repository at this point in the history
* Base Node object has `created_at` which indicates the `datetime` the
  node was launched/started/created.
* EC2, Digital Ocean, OpenStack fill this attribute.
* Nodes at drivers that do not (yet) support it have `NoneType` as date.
* Document changes.

closes #698

[GITHUB-698]

Signed-off-by: Allard Hoeve <allardhoeve@gmail.com>
  • Loading branch information
allardhoeve committed Feb 12, 2016
1 parent 6d2a3bb commit 72399b4
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 11 deletions.
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ Compute
(GITHUB-697)
[Rick van de Loo]

- Added `Node.create_at` which, on supported drivers, contains the datetime the
node was first started.
(GITHUB-698)
[Allard Hoeve]

Storage
~~~~~~~

Expand Down
6 changes: 5 additions & 1 deletion libcloud/compute/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class Node(UuidMixin):
"""

def __init__(self, id, name, state, public_ips, private_ips,
driver, size=None, image=None, extra=None):
driver, size=None, image=None, extra=None, created_at=None):
"""
:param id: Node ID.
:type id: ``str``
Expand All @@ -193,6 +193,9 @@ def __init__(self, id, name, state, public_ips, private_ips,
:param image: Image of this node. (optional)
:type size: :class:`.NodeImage`
:param created_at: The datetime this node was created (optional)
:type created_at: :class: `datetime.datetime`
:param extra: Optional provider specific attributes associated with
this node.
:type extra: ``dict``
Expand All @@ -205,6 +208,7 @@ def __init__(self, id, name, state, public_ips, private_ips,
self.private_ips = private_ips if private_ips else []
self.driver = driver
self.size = size
self.created_at = created_at
self.image = image
self.extra = extra or {}
UuidMixin.__init__(self)
Expand Down
4 changes: 3 additions & 1 deletion libcloud/compute/drivers/digitalocean.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import json
import warnings

from libcloud.utils.iso8601 import parse_date
from libcloud.utils.py3 import httplib

from libcloud.common.digitalocean import DigitalOcean_v1_BaseDriver
Expand Down Expand Up @@ -551,6 +552,7 @@ def _to_node(self, data):
else:
state = NodeState.UNKNOWN

created = parse_date(data['created_at'])
networks = data['networks']
private_ips = []
public_ips = []
Expand All @@ -568,7 +570,7 @@ def _to_node(self, data):

node = Node(id=data['id'], name=data['name'], state=state,
public_ips=public_ips, private_ips=private_ips,
driver=self, extra=extra)
created_at=created, driver=self, extra=extra)
return node

def _to_image(self, data):
Expand Down
5 changes: 4 additions & 1 deletion libcloud/compute/drivers/ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -5390,6 +5390,8 @@ def _to_node(self, element):
except KeyError:
state = NodeState.UNKNOWN

created = parse_date(findtext(element=element, xpath='launchTime',
namespace=NAMESPACE))
instance_id = findtext(element=element, xpath='instanceId',
namespace=NAMESPACE)
public_ip = findtext(element=element, xpath='ipAddress',
Expand Down Expand Up @@ -5421,7 +5423,8 @@ def _to_node(self, element):

return Node(id=instance_id, name=name, state=state,
public_ips=public_ips, private_ips=private_ips,
driver=self.connection.driver, extra=extra)
driver=self.connection.driver, created_at=created,
extra=extra)

def _to_images(self, object):
return [self._to_image(el) for el in object.findall(
Expand Down
2 changes: 2 additions & 0 deletions libcloud/compute/drivers/openstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -2096,6 +2096,7 @@ def _to_node(self, api_node):
image_id = image.get('id', None) if image else None
config_drive = api_node.get("config_drive", False)
volumes_attached = api_node.get('os-extended-volumes:volumes_attached')
created = parse_date(api_node["created"])

return Node(
id=api_node['id'],
Expand All @@ -2104,6 +2105,7 @@ def _to_node(self, api_node):
NodeState.UNKNOWN),
public_ips=public_ips,
private_ips=private_ips,
created_at=created,
driver=self,
extra=dict(
hostId=api_node['hostId'],
Expand Down
4 changes: 4 additions & 0 deletions libcloud/test/compute/test_digitalocean_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ def test_list_nodes_success(self):
self.assertEqual(nodes[0].extra['image_id'], 1601)
self.assertEqual(nodes[0].extra['size_id'], 66)

def test_list_nodes_does_not_support_created_datetime(self):
nodes = self.driver.list_nodes()
self.assertIsNone(nodes[0].created_at)

def test_create_node_invalid_size(self):
image = NodeImage(id='invalid', name=None, driver=self.driver)
size = self.driver.list_sizes()[0]
Expand Down
7 changes: 7 additions & 0 deletions libcloud/test/compute/test_digitalocean_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
import sys
import unittest

from datetime import datetime
from libcloud.utils.iso8601 import UTC

try:
import simplejson as json
except ImportError:
Expand Down Expand Up @@ -87,6 +90,10 @@ def test_list_nodes_success(self):
self.assertEqual(nodes[0].extra['image']['id'], 6918990)
self.assertEqual(nodes[0].extra['size_slug'], '512mb')

def test_list_nodes_fills_created_datetime(self):
nodes = self.driver.list_nodes()
self.assertEqual(nodes[0].created_at, datetime(2014, 11, 14, 16, 29, 21, tzinfo=UTC))

def test_create_node_invalid_size(self):
image = NodeImage(id='invalid', name=None, driver=self.driver)
size = self.driver.list_sizes()[0]
Expand Down
20 changes: 12 additions & 8 deletions libcloud/test/compute/test_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,10 @@ def test_list_nodes(self):
self.assertEqual(node.id, 'i-4382922a')
self.assertEqual(node.name, node.id)
self.assertEqual(len(node.public_ips), 2)
self.assertEqual(node.extra['launch_time'],
'2013-12-02T11:58:11.000Z')

self.assertEqual(node.extra['launch_time'], '2013-12-02T11:58:11.000Z')
self.assertEqual(node.created_at, datetime(2013, 12, 2, 11, 58, 11, tzinfo=UTC))

self.assertTrue('instance_type' in node.extra)
self.assertEqual(node.extra['availability'], 'us-east-1d')
self.assertEqual(node.extra['key_name'], 'fauxkey')
Expand All @@ -243,12 +245,14 @@ def test_list_nodes(self):
self.assertEqual(ret_node2.extra['subnet_id'], 'subnet-5fd9d412')
self.assertEqual(ret_node2.extra['vpc_id'], 'vpc-61dcd30e')
self.assertEqual(ret_node2.extra['tags']['Group'], 'VPC Test')
self.assertEqual(ret_node1.extra['launch_time'],
'2013-12-02T11:58:11.000Z')
self.assertTrue('instance_type' in ret_node1.extra)
self.assertEqual(ret_node2.extra['launch_time'],
'2013-12-02T15:58:29.000Z')
self.assertTrue('instance_type' in ret_node2.extra)

self.assertEqual(ret_node1.extra['launch_time'], '2013-12-02T11:58:11.000Z')
self.assertEqual(ret_node1.created_at, datetime(2013, 12, 2, 11, 58, 11, tzinfo=UTC))
self.assertEqual(ret_node2.extra['launch_time'], '2013-12-02T15:58:29.000Z')
self.assertEqual(ret_node2.created_at, datetime(2013, 12, 2, 15, 58, 29, tzinfo=UTC))

self.assertIn('instance_type', ret_node1.extra)
self.assertIn('instance_type', ret_node2.extra)

def test_ex_list_reserved_nodes(self):
node = self.driver.ex_list_reserved_nodes()[0]
Expand Down
3 changes: 3 additions & 0 deletions libcloud/test/compute/test_openstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,9 @@ def test_list_nodes(self):
self.assertTrue(
'fec0:4801:7808:52:16:3eff:fe60:187d' in node.private_ips)

# test creation date
self.assertEqual(node.created_at, datetime.datetime(2011, 10, 11, 0, 51, 39, tzinfo=UTC))

self.assertEqual(node.extra.get('flavorId'), '2')
self.assertEqual(node.extra.get('imageId'), '7')
self.assertEqual(node.extra.get('metadata'), {})
Expand Down

0 comments on commit 72399b4

Please sign in to comment.